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 /archival/unzip.c | |
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>
Diffstat (limited to 'archival/unzip.c')
-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); |