diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-04-17 21:05:34 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-04-17 21:05:34 +0200 |
| commit | 0ccf52a9fb9fa2f76eacbb6f1ef8419220557a40 (patch) | |
| tree | b1255e1f73791c91f5885ece2f75617385d3ed23 | |
| parent | 84ba50c32f7dbfccddd5c5ca34d48d97c3f72193 (diff) | |
| download | busybox-w32-0ccf52a9fb9fa2f76eacbb6f1ef8419220557a40.tar.gz busybox-w32-0ccf52a9fb9fa2f76eacbb6f1ef8419220557a40.tar.bz2 busybox-w32-0ccf52a9fb9fa2f76eacbb6f1ef8419220557a40.zip | |
unzip: fix a case where we find wrong CDE. Closes 8821
function old new delta
unzip_main 2472 2490 +18
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | archival/unzip.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/archival/unzip.c b/archival/unzip.c index f41ab6f44..b0a6ca836 100644 --- a/archival/unzip.c +++ b/archival/unzip.c | |||
| @@ -45,6 +45,12 @@ | |||
| 45 | #include "libbb.h" | 45 | #include "libbb.h" |
| 46 | #include "bb_archive.h" | 46 | #include "bb_archive.h" |
| 47 | 47 | ||
| 48 | #if 0 | ||
| 49 | # define dbg(...) bb_error_msg(__VA_ARGS__) | ||
| 50 | #else | ||
| 51 | # define dbg(...) ((void)0) | ||
| 52 | #endif | ||
| 53 | |||
| 48 | enum { | 54 | enum { |
| 49 | #if BB_BIG_ENDIAN | 55 | #if BB_BIG_ENDIAN |
| 50 | ZIP_FILEHEADER_MAGIC = 0x504b0304, | 56 | ZIP_FILEHEADER_MAGIC = 0x504b0304, |
| @@ -193,15 +199,17 @@ static uint32_t find_cdf_offset(void) | |||
| 193 | unsigned char *p; | 199 | unsigned char *p; |
| 194 | off_t end; | 200 | off_t end; |
| 195 | unsigned char *buf = xzalloc(PEEK_FROM_END); | 201 | unsigned char *buf = xzalloc(PEEK_FROM_END); |
| 202 | uint32_t found; | ||
| 196 | 203 | ||
| 197 | end = xlseek(zip_fd, 0, SEEK_END); | 204 | end = xlseek(zip_fd, 0, SEEK_END); |
| 198 | end -= PEEK_FROM_END; | 205 | end -= PEEK_FROM_END; |
| 199 | if (end < 0) | 206 | if (end < 0) |
| 200 | end = 0; | 207 | end = 0; |
| 201 | xlseek(zip_fd, end, SEEK_SET); | 208 | dbg("Looking for cdf_offset starting from 0x%"OFF_FMT"x", end); |
| 209 | xlseek(zip_fd, end, SEEK_SET); | ||
| 202 | full_read(zip_fd, buf, PEEK_FROM_END); | 210 | full_read(zip_fd, buf, PEEK_FROM_END); |
| 203 | 211 | ||
| 204 | cde_header.formatted.cdf_offset = BAD_CDF_OFFSET; | 212 | found = BAD_CDF_OFFSET; |
| 205 | p = buf; | 213 | p = buf; |
| 206 | while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) { | 214 | while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) { |
| 207 | if (*p != 'P') { | 215 | if (*p != 'P') { |
| @@ -220,14 +228,25 @@ static uint32_t find_cdf_offset(void) | |||
| 220 | /* | 228 | /* |
| 221 | * I've seen .ZIP files with seemingly valid CDEs | 229 | * I've seen .ZIP files with seemingly valid CDEs |
| 222 | * where cdf_offset points past EOF - ?? | 230 | * where cdf_offset points past EOF - ?? |
| 223 | * Ignore such CDEs: | 231 | * This check ignores such CDEs: |
| 224 | */ | 232 | */ |
| 225 | if (cde_header.formatted.cdf_offset < end + (p - buf)) | 233 | if (cde_header.formatted.cdf_offset < end + (p - buf)) { |
| 226 | break; | 234 | found = cde_header.formatted.cdf_offset; |
| 227 | cde_header.formatted.cdf_offset = BAD_CDF_OFFSET; | 235 | dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x", |
| 236 | (unsigned)found, end + (p-3 - buf)); | ||
| 237 | dbg(" cdf_offset+cdf_size:0x%x", | ||
| 238 | (unsigned)(found + SWAP_LE32(cde_header.formatted.cdf_size))); | ||
| 239 | /* | ||
| 240 | * We do not "break" here because only the last CDE is valid. | ||
| 241 | * I've seen a .zip archive which contained a .zip file, | ||
| 242 | * uncompressed, and taking the first CDE was using | ||
| 243 | * the CDE inside that file! | ||
| 244 | */ | ||
| 245 | } | ||
| 228 | } | 246 | } |
| 229 | free(buf); | 247 | free(buf); |
| 230 | return cde_header.formatted.cdf_offset; | 248 | dbg("Found cdf_offset:0x%x", (unsigned)found); |
| 249 | return found; | ||
| 231 | }; | 250 | }; |
| 232 | 251 | ||
| 233 | static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) | 252 | static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) |
| @@ -240,9 +259,13 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) | |||
| 240 | cdf_offset = find_cdf_offset(); | 259 | cdf_offset = find_cdf_offset(); |
| 241 | 260 | ||
| 242 | if (cdf_offset != BAD_CDF_OFFSET) { | 261 | if (cdf_offset != BAD_CDF_OFFSET) { |
| 262 | dbg("Reading CDF at 0x%x", (unsigned)cdf_offset); | ||
| 243 | xlseek(zip_fd, cdf_offset + 4, SEEK_SET); | 263 | xlseek(zip_fd, cdf_offset + 4, SEEK_SET); |
| 244 | xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); | 264 | xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); |
| 245 | FIX_ENDIANNESS_CDF(*cdf_ptr); | 265 | FIX_ENDIANNESS_CDF(*cdf_ptr); |
| 266 | dbg("file_name_length:%u", (unsigned)cdf_ptr->formatted.file_name_length); | ||
| 267 | dbg("extra_field_length:%u", (unsigned)cdf_ptr->formatted.extra_field_length); | ||
| 268 | dbg("file_comment_length:%u", (unsigned)cdf_ptr->formatted.file_comment_length); | ||
| 246 | cdf_offset += 4 + CDF_HEADER_LEN | 269 | cdf_offset += 4 + CDF_HEADER_LEN |
| 247 | + cdf_ptr->formatted.file_name_length | 270 | + cdf_ptr->formatted.file_name_length |
| 248 | + cdf_ptr->formatted.extra_field_length | 271 | + cdf_ptr->formatted.extra_field_length |
| @@ -532,11 +555,14 @@ int unzip_main(int argc, char **argv) | |||
| 532 | /* Check magic number */ | 555 | /* Check magic number */ |
| 533 | xread(zip_fd, &magic, 4); | 556 | xread(zip_fd, &magic, 4); |
| 534 | /* Central directory? It's at the end, so exit */ | 557 | /* Central directory? It's at the end, so exit */ |
| 535 | if (magic == ZIP_CDF_MAGIC) | 558 | if (magic == ZIP_CDF_MAGIC) { |
| 559 | dbg("got ZIP_CDF_MAGIC"); | ||
| 536 | break; | 560 | break; |
| 561 | } | ||
| 537 | #if ENABLE_DESKTOP | 562 | #if ENABLE_DESKTOP |
| 538 | /* Data descriptor? It was a streaming file, go on */ | 563 | /* Data descriptor? It was a streaming file, go on */ |
| 539 | if (magic == ZIP_DD_MAGIC) { | 564 | if (magic == ZIP_DD_MAGIC) { |
| 565 | dbg("got ZIP_DD_MAGIC"); | ||
| 540 | /* skip over duplicate crc32, cmpsize and ucmpsize */ | 566 | /* skip over duplicate crc32, cmpsize and ucmpsize */ |
| 541 | unzip_skip(3 * 4); | 567 | unzip_skip(3 * 4); |
| 542 | continue; | 568 | continue; |
| @@ -544,6 +570,7 @@ int unzip_main(int argc, char **argv) | |||
| 544 | #endif | 570 | #endif |
| 545 | if (magic != ZIP_FILEHEADER_MAGIC) | 571 | if (magic != ZIP_FILEHEADER_MAGIC) |
| 546 | bb_error_msg_and_die("invalid zip magic %08X", (int)magic); | 572 | bb_error_msg_and_die("invalid zip magic %08X", (int)magic); |
| 573 | dbg("got ZIP_FILEHEADER_MAGIC"); | ||
| 547 | 574 | ||
| 548 | /* Read the file header */ | 575 | /* Read the file header */ |
| 549 | xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); | 576 | xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN); |
