aboutsummaryrefslogtreecommitdiff
path: root/archival/unzip.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-04-17 21:05:34 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-04-17 21:05:34 +0200
commit0ccf52a9fb9fa2f76eacbb6f1ef8419220557a40 (patch)
treeb1255e1f73791c91f5885ece2f75617385d3ed23 /archival/unzip.c
parent84ba50c32f7dbfccddd5c5ca34d48d97c3f72193 (diff)
downloadbusybox-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.c43
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
48enum { 54enum {
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
233static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) 252static 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);