1 diff -up unzip60/crc_i386.S.exec-shield unzip60/crc_i386.S
2 --- unzip60/crc_i386.S.exec-shield 2007-01-07 06:02:58.000000000 +0100
3 +++ unzip60/crc_i386.S 2009-11-18 11:16:39.630389312 +0100
4 @@ -302,3 +302,6 @@ _crc32: /* ulg c
5 #endif /* i386 || _i386 || _I386 || __i386 */
6
7 #endif /* !USE_ZLIB && !CRC_TABLE_ONLY */
8 +
9 +.section .note.GNU-stack, "", @progbits
10 +.previous
11 diff -up unzip60/extract.c.close unzip60/extract.c
12 --- unzip60/extract.c.close 2009-03-14 02:32:52.000000000 +0100
13 +++ unzip60/extract.c 2009-11-19 08:17:23.481263496 +0100
14 @@ -1924,24 +1924,21 @@ static int extract_or_test_member(__G)
15
16 #ifdef VMS /* VMS: required even for stdout! (final flush) */
17 if (!uO.tflag) /* don't close NULL file */
18 - close_outfile(__G);
19 + error = close_outfile(__G);
20 #else
21 #ifdef DLL
22 if (!uO.tflag && (!uO.cflag || G.redirect_data)) {
23 if (G.redirect_data)
24 FINISH_REDIRECT();
25 else
26 - close_outfile(__G);
27 + error = close_outfile(__G);
28 }
29 #else
30 if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */
31 - close_outfile(__G);
32 + error = close_outfile(__G);
33 #endif
34 #endif /* VMS */
35
36 - /* GRR: CONVERT close_outfile() TO NON-VOID: CHECK FOR ERRORS! */
37 -
38 -
39 if (G.disk_full) { /* set by flush() */
40 if (G.disk_full > 1) {
41 #if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
42 diff -up unzip60/unix/unix.c.close unzip60/unix/unix.c
43 --- unzip60/unix/unix.c.close 2009-01-24 00:31:26.000000000 +0100
44 +++ unzip60/unix/unix.c 2009-11-19 08:33:25.568389171 +0100
45 @@ -1096,10 +1096,41 @@ static int get_extattribs(__G__ pzt, z_u
46 #ifndef MTS
47
48 /****************************/
49 +/* Function CloseError() */
50 +/***************************/
51 +
52 +int CloseError(__G)
53 + __GDEF
54 +{
55 + int errval = PK_OK;
56 +
57 + if (fclose(G.outfile) < 0) {
58 + switch (errno) {
59 + case ENOSPC:
60 + /* Do we need this on fileio.c? */
61 + Info(slide, 0x4a1, ((char *)slide, "%s: write error (disk full?). Continue? (y/n/^C) ",
62 + FnFilter1(G.filename)));
63 + fgets(G.answerbuf, 9, stdin);
64 + if (*G.answerbuf == 'y') /* stop writing to this file */
65 + G.disk_full = 1; /* pass to next */
66 + else
67 + G.disk_full = 2; /* no: exit program */
68 +
69 + errval = PK_DISK;
70 + break;
71 +
72 + default:
73 + errval = PK_WARN;
74 + }
75 + }
76 + return errval;
77 +} /* End of CloseError() */
78 +
79 +/****************************/
80 /* Function close_outfile() */
81 /****************************/
82
83 -void close_outfile(__G) /* GRR: change to return PK-style warning level */
84 +int close_outfile(__G)
85 __GDEF
86 {
87 union {
88 @@ -1108,6 +1139,7 @@ void close_outfile(__G) /* GRR: chang
89 } zt;
90 ulg z_uidgid[2];
91 int have_uidgid_flg;
92 + int errval = PK_OK;
93
94 have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid);
95
96 @@ -1141,16 +1173,16 @@ void close_outfile(__G) /* GRR: chang
97 Info(slide, 0x201, ((char *)slide,
98 "warning: symbolic link (%s) failed: mem alloc overflow\n",
99 FnFilter1(G.filename)));
100 - fclose(G.outfile);
101 - return;
102 + errval = CloseError(G.outfile, G.filename);
103 + return errval ? errval : PK_WARN;
104 }
105
106 if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) {
107 Info(slide, 0x201, ((char *)slide,
108 "warning: symbolic link (%s) failed: no mem\n",
109 FnFilter1(G.filename)));
110 - fclose(G.outfile);
111 - return;
112 + errval = CloseError(G.outfile, G.filename);
113 + return errval ? errval : PK_WARN;
114 }
115 slnk_entry->next = NULL;
116 slnk_entry->targetlen = ucsize;
117 @@ -1174,10 +1206,10 @@ void close_outfile(__G) /* GRR: chang
118 "warning: symbolic link (%s) failed\n",
119 FnFilter1(G.filename)));
120 free(slnk_entry);
121 - fclose(G.outfile);
122 - return;
123 + errval = CloseError(G.outfile, G.filename);
124 + return errval ? errval : PK_WARN;
125 }
126 - fclose(G.outfile); /* close "link" file for good... */
127 + errval = CloseError(G.outfile, G.filename); /* close "link" file for good... */
128 slnk_entry->target[ucsize] = '\0';
129 if (QCOND2)
130 Info(slide, 0, ((char *)slide, "-> %s ",
131 @@ -1188,7 +1220,7 @@ void close_outfile(__G) /* GRR: chang
132 else
133 G.slink_head = slnk_entry;
134 G.slink_last = slnk_entry;
135 - return;
136 + return errval;
137 }
138 #endif /* SYMLINKS */
139
140 @@ -1201,7 +1233,7 @@ void close_outfile(__G) /* GRR: chang
141 #endif
142
143 #if (defined(NO_FCHOWN))
144 - fclose(G.outfile);
145 + errval = CloseError(G.outfile, G.filename);
146 #endif
147
148 /* if -X option was specified and we have UID/GID info, restore it */
149 @@ -1227,7 +1259,7 @@ void close_outfile(__G) /* GRR: chang
150 }
151
152 #if (!defined(NO_FCHOWN) && defined(NO_FCHMOD))
153 - fclose(G.outfile);
154 + errval = CloseError(G.outfile, G.filename);
155 #endif
156
157 #if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD))
158 @@ -1239,7 +1271,7 @@ void close_outfile(__G) /* GRR: chang
159 if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr)))
160 perror("fchmod (file attributes) error");
161
162 - fclose(G.outfile);
163 + errval = CloseError(G.outfile, G.filename);
164 #endif /* !NO_FCHOWN && !NO_FCHMOD */
165
166 /* skip restoring time stamps on user's request */
167 @@ -1267,6 +1299,7 @@ void close_outfile(__G) /* GRR: chang
168 #endif
169 #endif /* NO_FCHOWN || NO_FCHMOD */
170
171 + return errval;
172 } /* end function close_outfile() */
173
174 #endif /* !MTS */
175 diff -up unzip60/unzpriv.h.close unzip60/unzpriv.h
176 --- unzip60/unzpriv.h.close 2009-04-20 01:59:26.000000000 +0200
177 +++ unzip60/unzpriv.h 2009-11-19 08:19:08.610388618 +0100
178 @@ -2604,7 +2604,7 @@ char *GetLoadPath OF((__GPRO));
179 int SetFileSize OF((FILE *file, zusz_t filesize)); /* local */
180 #endif
181 #ifndef MTS /* macro in MTS */
182 - void close_outfile OF((__GPRO)); /* local */
183 + int close_outfile OF((__GPRO)); /* local */
184 #endif
185 #ifdef SET_SYMLINK_ATTRIBS
186 int set_symlnk_attribs OF((__GPRO__ slinkentry *slnk_entry)); /* local */
187 diff -up unzip60/zipinfo.c.attribs-overflow unzip60/zipinfo.c
188 --- unzip60/zipinfo.c.attribs-overflow 2009-11-30 09:55:39.000000000 +0100
189 +++ unzip60/zipinfo.c 2009-11-30 09:56:42.844263244 +0100
190 @@ -1881,7 +1881,7 @@ static int zi_short(__G) /* return PK-
191 #endif
192 int k, error, error_in_archive=PK_COOL;
193 unsigned hostnum, hostver, methid, methnum, xattr;
194 - char *p, workspace[12], attribs[16];
195 + char *p, workspace[12], attribs[17];
196 char methbuf[5];
197 static ZCONST char dtype[5]="NXFS"; /* normal, maximum, fast, superfast */
198 static ZCONST char Far os[NUM_HOSTS+1][4] = {
199 diff --git a/process.c b/process.c
200 index 1e9a1e1..905732b 100644
201 --- a/process.c
202 +++ b/process.c
203 @@ -1751,6 +1751,12 @@ int process_cdir_file_hdr(__G) /* return PK-type error code */
204 = (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11);
205 #endif
206
207 +#ifdef SYMLINKS
208 + /* Initialize the symlink flag, may be set by the platform-specific
209 + mapattr function. */
210 + G.pInfo->symlink = 0;
211 +#endif
212 +
213 return PK_COOL;
214
215 } /* end function process_cdir_file_hdr() */
216 diff --git a/extract.c b/extract.c
217 index eeb2f57..a0a4929 100644
218 --- a/extract.c
219 +++ b/extract.c
220 @@ -472,8 +472,8 @@ int extract_or_test_files(__G) /* return PK-type error code */
221 */
222 Info(slide, 0x401, ((char *)slide,
223 LoadFarString(CentSigMsg), j + blknum*DIR_BLKSIZ + 1));
224 - Info(slide, 0x401, ((char *)slide,
225 - LoadFarString(ReportMsg)));
226 + Info(slide, 0x401,
227 + ((char *)slide,"%s", LoadFarString(ReportMsg)));
228 error_in_archive = PK_BADERR;
229 }
230 reached_end = TRUE; /* ...so no more left to do */
231 @@ -752,8 +752,8 @@ int extract_or_test_files(__G) /* return PK-type error code */
232
233 #ifndef SFX
234 if (no_endsig_found) { /* just to make sure */
235 - Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
236 - Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg)));
237 + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg)));
238 + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(ReportMsg)));
239 if (!error_in_archive) /* don't overwrite stronger error */
240 error_in_archive = PK_WARN;
241 }
242 diff --git a/list.c b/list.c
243 index 15e0011..f7359c3 100644
244 --- a/list.c
245 +++ b/list.c
246 @@ -181,7 +181,7 @@ int list_files(__G) /* return PK-type error code */
247 Info(slide, 0x401,
248 ((char *)slide, LoadFarString(CentSigMsg), j));
249 Info(slide, 0x401,
250 - ((char *)slide, LoadFarString(ReportMsg)));
251 + ((char *)slide,"%s", LoadFarString(ReportMsg)));
252 return PK_BADERR; /* sig not found */
253 }
254 }
255 @@ -507,7 +507,8 @@ int list_files(__G) /* return PK-type error code */
256 && (!G.ecrec.is_zip64_archive)
257 && (memcmp(G.sig, end_central_sig, 4) != 0)
258 ) { /* just to make sure again */
259 - Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
260 + Info(slide, 0x401,
261 + ((char *)slide,"%s", LoadFarString(EndSigMsg)));
262 error_in_archive = PK_WARN; /* didn't find sig */
263 }
264
265 @@ -591,7 +592,7 @@ int get_time_stamp(__G__ last_modtime, nmember) /* return PK-type error code */
266 Info(slide, 0x401,
267 ((char *)slide, LoadFarString(CentSigMsg), j));
268 Info(slide, 0x401,
269 - ((char *)slide, LoadFarString(ReportMsg)));
270 + ((char *)slide,"%s", LoadFarString(ReportMsg)));
271 return PK_BADERR; /* sig not found */
272 }
273 }
274 @@ -674,7 +675,7 @@ int get_time_stamp(__G__ last_modtime, nmember) /* return PK-type error code */
275 ---------------------------------------------------------------------------*/
276
277 if (memcmp(G.sig, end_central_sig, 4)) { /* just to make sure again */
278 - Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
279 + Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg)));
280 error_in_archive = PK_WARN;
281 }
282 if (*nmember == 0L && error_in_archive <= PK_WARN)
283 diff --git a/zipinfo.c b/zipinfo.c
284 index 6e22cc8..ac5c61b 100644
285 --- a/zipinfo.c
286 +++ b/zipinfo.c
287 @@ -771,7 +771,7 @@ int zipinfo(__G) /* return PK-type error code */
288 Info(slide, 0x401,
289 ((char *)slide, LoadFarString(CentSigMsg), j));
290 Info(slide, 0x401,
291 - ((char *)slide, LoadFarString(ReportMsg)));
292 + ((char *)slide,"%s", LoadFarString(ReportMsg)));
293 error_in_archive = PK_BADERR; /* sig not found */
294 break;
295 }
296 @@ -960,7 +960,8 @@ int zipinfo(__G) /* return PK-type error code */
297 && (!G.ecrec.is_zip64_archive)
298 && (memcmp(G.sig, end_central_sig, 4) != 0)
299 ) { /* just to make sure again */
300 - Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
301 + Info(slide, 0x401,
302 + ((char *)slide,"%s", LoadFarString(EndSigMsg)));
303 error_in_archive = PK_WARN; /* didn't find sig */
304 }
305
306 diff --git a/fileio.c b/fileio.c
307 index ba0a1d0..03fc4be 100644
308 --- a/fileio.c
309 +++ b/fileio.c
310 @@ -2006,6 +2006,7 @@ int do_string(__G__ length, option) /* return PK-type error code */
311 unsigned comment_bytes_left;
312 unsigned int block_len;
313 int error=PK_OK;
314 + unsigned int length2;
315 #ifdef AMIGA
316 char tmp_fnote[2 * AMIGA_FILENOTELEN]; /* extra room for squozen chars */
317 #endif
318 @@ -2292,8 +2293,12 @@ int do_string(__G__ length, option) /* return PK-type error code */
319 seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
320 (G.inptr-G.inbuf) + length);
321 } else {
322 - if (readbuf(__G__ (char *)G.extra_field, length) == 0)
323 + if ((length2 = readbuf(__G__ (char *)G.extra_field, length)) == 0)
324 return PK_EOF;
325 + if(length2 < length) {
326 + memset (__G__ (char *)G.extra_field+length2, 0 , length-length2);
327 + length = length2;
328 + }
329 /* Looks like here is where extra fields are read */
330 getZip64Data(__G__ G.extra_field, length);
331 #ifdef UNICODE_SUPPORT
332 --- ./process.c.orig 2009-03-06 02:25:10.000000000 +0100
333 +++ ./process.c 2013-09-12 10:51:16.000000000 +0200
334 @@ -2901,9 +2901,9 @@
335 */
336
337 #ifdef IZ_HAVE_UXUIDGID
338 - if (eb_len >= EB_UX3_MINLEN
339 - && z_uidgid != NULL
340 - && (*((EB_HEADSIZE + 0) + ef_buf) == 1)
341 + if ((eb_len >= EB_UX3_MINLEN)
342 + && (z_uidgid != NULL)
343 + && ((*((EB_HEADSIZE + 0) + ef_buf) == 1)))
344 /* only know about version 1 */
345 {
346 uch uid_size;
347 @@ -2915,10 +2915,10 @@
348 flags &= ~0x0ff; /* ignore any previous UNIX field */
349
350 if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf,
351 - uid_size, z_uidgid[0])
352 + uid_size, &z_uidgid[0])
353 &&
354 read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf,
355 - gid_size, z_uidgid[1]) )
356 + gid_size, &z_uidgid[1]) )
357 {
358 flags |= EB_UX2_VALID; /* signal success */
359 }
360 diff --git a/extract.c b/extract.c
361 index a0a4929..9ef80b3 100644
362 --- a/extract.c
363 +++ b/extract.c
364 @@ -2214,6 +2214,7 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
365 ulg eb_ucsize;
366 uch *eb_ucptr;
367 int r;
368 + ush method;
369
370 if (compr_offset < 4) /* field is not compressed: */
371 return PK_OK; /* do nothing and signal OK */
372 @@ -2223,6 +2224,12 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
373 eb_size <= (compr_offset + EB_CMPRHEADLEN)))
374 return IZ_EF_TRUNC; /* no compressed data! */
375
376 + method = makeword(eb + (EB_HEADSIZE + compr_offset));
377 + if ((method == STORED) && (eb_size != compr_offset + EB_CMPRHEADLEN + eb_ucsize))
378 + return PK_ERR; /* compressed & uncompressed
379 + * should match in STORED
380 + * method */
381 +
382 if (
383 #ifdef INT_16BIT
384 (((ulg)(extent)eb_ucsize) != eb_ucsize) ||
385 diff --git a/extract.c b/extract.c
386 index 9ef80b3..c741b5f 100644
387 --- a/extract.c
388 +++ b/extract.c
389 @@ -1,5 +1,5 @@
390 /*
391 - Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
392 + Copyright (c) 1990-2014 Info-ZIP. All rights reserved.
393
394 See the accompanying file LICENSE, version 2009-Jan-02 or later
395 (the contents of which are also included in unzip.h) for terms of use.
396 @@ -298,6 +298,8 @@ char ZCONST Far TruncNTSD[] =
397 #ifndef SFX
398 static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \
399 EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
400 + static ZCONST char Far TooSmallEBlength[] = "bad extra-field entry:\n \
401 + EF block length (%u bytes) invalid (< %d)\n";
402 static ZCONST char Far InvalidComprDataEAs[] =
403 " invalid compressed data for EAs\n";
404 # if (defined(WIN32) && defined(NTSD_EAS))
405 @@ -2020,7 +2022,8 @@ static int TestExtraField(__G__ ef, ef_len)
406 ebID = makeword(ef);
407 ebLen = (unsigned)makeword(ef+EB_LEN);
408
409 - if (ebLen > (ef_len - EB_HEADSIZE)) {
410 + if (ebLen > (ef_len - EB_HEADSIZE))
411 + {
412 /* Discovered some extra field inconsistency! */
413 if (uO.qflag)
414 Info(slide, 1, ((char *)slide, "%-22s ",
415 @@ -2155,11 +2158,29 @@ static int TestExtraField(__G__ ef, ef_len)
416 }
417 break;
418 case EF_PKVMS:
419 - if (makelong(ef+EB_HEADSIZE) !=
420 - crc32(CRCVAL_INITIAL, ef+(EB_HEADSIZE+4),
421 - (extent)(ebLen-4)))
422 - Info(slide, 1, ((char *)slide,
423 - LoadFarString(BadCRC_EAs)));
424 + /* 2015-01-30 SMS. Added sufficient-bytes test/message
425 + * here. (Removed defective ebLen test above.)
426 + *
427 + * If sufficient bytes (EB_PKVMS_MINLEN) are available,
428 + * then compare the stored CRC value with the calculated
429 + * CRC for the remainder of the data (and complain about
430 + * a mismatch).
431 + */
432 + if (ebLen < EB_PKVMS_MINLEN)
433 + {
434 + /* Insufficient bytes available. */
435 + Info( slide, 1,
436 + ((char *)slide, LoadFarString( TooSmallEBlength),
437 + ebLen, EB_PKVMS_MINLEN));
438 + }
439 + else if (makelong(ef+ EB_HEADSIZE) !=
440 + crc32(CRCVAL_INITIAL,
441 + (ef+ EB_HEADSIZE+ EB_PKVMS_MINLEN),
442 + (extent)(ebLen- EB_PKVMS_MINLEN)))
443 + {
444 + Info(slide, 1, ((char *)slide,
445 + LoadFarString(BadCRC_EAs)));
446 + }
447 break;
448 case EF_PKW32:
449 case EF_PKUNIX:
450 diff --git a/unzpriv.h b/unzpriv.h
451 index 005cee0..5c83a6e 100644
452 --- a/unzpriv.h
453 +++ b/unzpriv.h
454 @@ -1806,6 +1806,8 @@
455 #define EB_NTSD_VERSION 4 /* offset of NTSD version byte */
456 #define EB_NTSD_MAX_VER (0) /* maximum version # we know how to handle */
457
458 +#define EB_PKVMS_MINLEN 4 /* minimum data length of PKVMS extra block */
459 +
460 #define EB_ASI_CRC32 0 /* offset of ASI Unix field's crc32 checksum */
461 #define EB_ASI_MODE 4 /* offset of ASI Unix permission mode field */
462
463
464 diff --git a/extract.c b/extract.c
465 index c741b5f..e4a4c7b 100644
466 --- a/extract.c
467 +++ b/extract.c
468 @@ -2240,10 +2240,17 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
469 if (compr_offset < 4) /* field is not compressed: */
470 return PK_OK; /* do nothing and signal OK */
471
472 + /* Return no/bad-data error status if any problem is found:
473 + * 1. eb_size is too small to hold the uncompressed size
474 + * (eb_ucsize). (Else extract eb_ucsize.)
475 + * 2. eb_ucsize is zero (invalid). 2014-12-04 SMS.
476 + * 3. eb_ucsize is positive, but eb_size is too small to hold
477 + * the compressed data header.
478 + */
479 if ((eb_size < (EB_UCSIZE_P + 4)) ||
480 - ((eb_ucsize = makelong(eb+(EB_HEADSIZE+EB_UCSIZE_P))) > 0L &&
481 - eb_size <= (compr_offset + EB_CMPRHEADLEN)))
482 - return IZ_EF_TRUNC; /* no compressed data! */
483 + ((eb_ucsize = makelong( eb+ (EB_HEADSIZE+ EB_UCSIZE_P))) == 0L) ||
484 + ((eb_ucsize > 0L) && (eb_size <= (compr_offset + EB_CMPRHEADLEN))))
485 + return IZ_EF_TRUNC; /* no/bad compressed data! */
486
487 method = makeword(eb + (EB_HEADSIZE + compr_offset));
488 if ((method == STORED) && (eb_size != compr_offset + EB_CMPRHEADLEN + eb_ucsize))
489 diff --git a/fileio.c b/fileio.c
490 index 03fc4be..2a61a30 100644
491 --- a/fileio.c
492 +++ b/fileio.c
493 @@ -176,6 +176,8 @@ static ZCONST char Far FilenameTooLongTrunc[] =
494 #endif
495 static ZCONST char Far ExtraFieldTooLong[] =
496 "warning: extra field too long (%d). Ignoring...\n";
497 +static ZCONST char Far ExtraFieldCorrupt[] =
498 + "warning: extra field (type: 0x%04x) corrupt. Continuing...\n";
499
500 #ifdef WINDLL
501 static ZCONST char Far DiskFullQuery[] =
502 @@ -2300,7 +2302,13 @@ int do_string(__G__ length, option) /* return PK-type error code */
503 length = length2;
504 }
505 /* Looks like here is where extra fields are read */
506 - getZip64Data(__G__ G.extra_field, length);
507 + if (getZip64Data(__G__ G.extra_field, length) != PK_COOL)
508 + {
509 + Info(slide, 0x401, ((char *)slide,
510 + LoadFarString( ExtraFieldCorrupt), EF_PKSZ64));
511 + error = PK_WARN;
512 + }
513 +
514 #ifdef UNICODE_SUPPORT
515 G.unipath_filename = NULL;
516 if (G.UzO.U_flag < 2) {
517 diff --git a/process.c b/process.c
518 index be6e006..0d57ab4 100644
519 --- a/process.c
520 +++ b/process.c
521 @@ -1,5 +1,5 @@
522 /*
523 - Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
524 + Copyright (c) 1990-2014 Info-ZIP. All rights reserved.
525
526 See the accompanying file LICENSE, version 2009-Jan-02 or later
527 (the contents of which are also included in unzip.h) for terms of use.
528 @@ -1894,48 +1894,83 @@ int getZip64Data(__G__ ef_buf, ef_len)
529 and a 4-byte version of disk start number.
530 Sets both local header and central header fields. Not terribly clever,
531 but it means that this procedure is only called in one place.
532 +
533 + 2014-12-05 SMS.
534 + Added checks to ensure that enough data are available before calling
535 + makeint64() or makelong(). Replaced various sizeof() values with
536 + simple ("4" or "8") constants. (The Zip64 structures do not depend
537 + on our variable sizes.) Error handling is crude, but we should now
538 + stay within the buffer.
539 ---------------------------------------------------------------------------*/
540
541 +#define Z64FLGS 0xffff
542 +#define Z64FLGL 0xffffffff
543 +
544 if (ef_len == 0 || ef_buf == NULL)
545 return PK_COOL;
546
547 Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n",
548 ef_len));
549
550 - while (ef_len >= EB_HEADSIZE) {
551 + while (ef_len >= EB_HEADSIZE)
552 + {
553 eb_id = makeword(EB_ID + ef_buf);
554 eb_len = makeword(EB_LEN + ef_buf);
555
556 - if (eb_len > (ef_len - EB_HEADSIZE)) {
557 - /* discovered some extra field inconsistency! */
558 + if (eb_len > (ef_len - EB_HEADSIZE))
559 + {
560 + /* Extra block length exceeds remaining extra field length. */
561 Trace((stderr,
562 "getZip64Data: block length %u > rest ef_size %u\n", eb_len,
563 ef_len - EB_HEADSIZE));
564 break;
565 }
566 - if (eb_id == EF_PKSZ64) {
567
568 + if (eb_id == EF_PKSZ64)
569 + {
570 int offset = EB_HEADSIZE;
571
572 - if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){
573 - G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf);
574 - offset += sizeof(G.crec.ucsize);
575 + if ((G.crec.ucsize == Z64FLGL) || (G.lrec.ucsize == Z64FLGL))
576 + {
577 + if (offset+ 8 > ef_len)
578 + return PK_ERR;
579 +
580 + G.crec.ucsize = G.lrec.ucsize = makeint64(offset + ef_buf);
581 + offset += 8;
582 }
583 - if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){
584 - G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf);
585 - offset += sizeof(G.crec.csize);
586 +
587 + if ((G.crec.csize == Z64FLGL) || (G.lrec.csize == Z64FLGL))
588 + {
589 + if (offset+ 8 > ef_len)
590 + return PK_ERR;
591 +
592 + G.csize = G.crec.csize = G.lrec.csize = makeint64(offset + ef_buf);
593 + offset += 8;
594 }
595 - if (G.crec.relative_offset_local_header == 0xffffffff){
596 +
597 + if (G.crec.relative_offset_local_header == Z64FLGL)
598 + {
599 + if (offset+ 8 > ef_len)
600 + return PK_ERR;
601 +
602 G.crec.relative_offset_local_header = makeint64(offset + ef_buf);
603 - offset += sizeof(G.crec.relative_offset_local_header);
604 + offset += 8;
605 }
606 - if (G.crec.disk_number_start == 0xffff){
607 +
608 + if (G.crec.disk_number_start == Z64FLGS)
609 + {
610 + if (offset+ 4 > ef_len)
611 + return PK_ERR;
612 +
613 G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf);
614 - offset += sizeof(G.crec.disk_number_start);
615 + offset += 4;
616 }
617 +#if 0
618 + break; /* Expect only one EF_PKSZ64 block. */
619 +#endif /* 0 */
620 }
621
622 - /* Skip this extra field block */
623 + /* Skip this extra field block. */
624 ef_buf += (eb_len + EB_HEADSIZE);
625 ef_len -= (eb_len + EB_HEADSIZE);
626 }
627 diff --git a/list.c b/list.c
628 index f7359c3..4c3d703 100644
629 --- a/list.c
630 +++ b/list.c
631 @@ -97,7 +97,7 @@ int list_files(__G) /* return PK-type error code */
632 {
633 int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
634 #ifndef WINDLL
635 - char sgn, cfactorstr[10];
636 + char sgn, cfactorstr[13];
637 int longhdr=(uO.vflag>1);
638 #endif
639 int date_format;
640 @@ -339,7 +339,19 @@ int list_files(__G) /* return PK-type error code */
641 G.crec.compression_method == ENHDEFLATED) {
642 methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3];
643 } else if (methnum >= NUM_METHODS) {
644 - sprintf(&methbuf[4], "%03u", G.crec.compression_method);
645 + /* 2013-02-26 SMS.
646 + * http://sourceforge.net/tracker/?func=detail
647 + * &aid=2861648&group_id=118012&atid=679786
648 + * Unexpectedly large compression methods overflow
649 + * &methbuf[]. Use the old, three-digit decimal format
650 + * for values which fit. Otherwise, sacrifice the
651 + * colon, and use four-digit hexadecimal.
652 + */
653 + if (G.crec.compression_method <= 999) {
654 + sprintf( &methbuf[ 4], "%03u", G.crec.compression_method);
655 + } else {
656 + sprintf( &methbuf[ 3], "%04X", G.crec.compression_method);
657 + }
658 }
659
660 #if 0 /* GRR/Euro: add this? */
661 From bdd4a0cecd745cb4825e4508b5bdf2579731086a Mon Sep 17 00:00:00 2001
662 From: Petr Stodulka <pstodulk@redhat.com>
663 Date: Mon, 14 Sep 2015 18:23:17 +0200
664 Subject: [PATCH 1/3] upstream fix for heap overflow
665
666 https://bugzilla.redhat.com/attachment.cgi?id=1073002
667 ---
668 crypt.c | 12 +++++++++++-
669 1 file changed, 11 insertions(+), 1 deletion(-)
670
671 diff --git a/crypt.c b/crypt.c
672 index 784e411..a8975f2 100644
673 --- a/crypt.c
674 +++ b/crypt.c
675 @@ -465,7 +465,17 @@ int decrypt(__G__ passwrd)
676 GLOBAL(pInfo->encrypted) = FALSE;
677 defer_leftover_input(__G);
678 for (n = 0; n < RAND_HEAD_LEN; n++) {
679 - b = NEXTBYTE;
680 + /* 2012-11-23 SMS. (OUSPG report.)
681 + * Quit early if compressed size < HEAD_LEN. The resulting
682 + * error message ("unable to get password") could be improved,
683 + * but it's better than trying to read nonexistent data, and
684 + * then continuing with a negative G.csize. (See
685 + * fileio.c:readbyte()).
686 + */
687 + if ((b = NEXTBYTE) == (ush)EOF)
688 + {
689 + return PK_ERR;
690 + }
691 h[n] = (uch)b;
692 Trace((stdout, " (%02x)", h[n]));
693 }
694 --
695 2.4.6
696
697
698 From 4b48844661ff9569f2ecf582a387d46a5775b5d8 Mon Sep 17 00:00:00 2001
699 From: Kamil Dudka <kdudka@redhat.com>
700 Date: Mon, 14 Sep 2015 18:24:56 +0200
701 Subject: [PATCH 2/3] fix infinite loop when extracting empty bzip2 data
702
703 Bug: https://sourceforge.net/p/infozip/patches/23/
704 ---
705 extract.c | 6 ++++++
706 1 file changed, 6 insertions(+)
707
708 diff --git a/extract.c b/extract.c
709 index 7134bfe..29db027 100644
710 --- a/extract.c
711 +++ b/extract.c
712 @@ -2733,6 +2733,12 @@ __GDEF
713 int repeated_buf_err;
714 bz_stream bstrm;
715
716 + if (G.incnt <= 0 && G.csize <= 0L) {
717 + /* avoid an infinite loop */
718 + Trace((stderr, "UZbunzip2() got empty input\n"));
719 + return 2;
720 + }
721 +
722 #if (defined(DLL) && !defined(NO_SLIDE_REDIR))
723 if (G.redirect_slide)
724 wsize = G.redirect_size, redirSlide = G.redirect_buffer;
725 --
726 2.4.6
727
728
729 From bd150334fb4084f5555a6be26b015a0671cb5b74 Mon Sep 17 00:00:00 2001
730 From: Kamil Dudka <kdudka@redhat.com>
731 Date: Tue, 22 Sep 2015 18:52:23 +0200
732 Subject: [PATCH 3/3] extract: prevent unsigned overflow on invalid input
733
734 Suggested-by: Stefan Cornelius
735 ---
736 extract.c | 11 ++++++++++-
737 1 file changed, 10 insertions(+), 1 deletion(-)
738
739 diff --git a/extract.c b/extract.c
740 index 29db027..b9ae667 100644
741 --- a/extract.c
742 +++ b/extract.c
743 @@ -1257,8 +1257,17 @@ static int extract_or_test_entrylist(__G__ numchunk,
744 if (G.lrec.compression_method == STORED) {
745 zusz_t csiz_decrypted = G.lrec.csize;
746
747 - if (G.pInfo->encrypted)
748 + if (G.pInfo->encrypted) {
749 + if (csiz_decrypted < 12) {
750 + /* handle the error now to prevent unsigned overflow */
751 + Info(slide, 0x401, ((char *)slide,
752 + LoadFarStringSmall(ErrUnzipNoFile),
753 + LoadFarString(InvalidComprData),
754 + LoadFarStringSmall2(Inflate)));
755 + return PK_ERR;
756 + }
757 csiz_decrypted -= 12;
758 + }
759 if (G.lrec.ucsize != csiz_decrypted) {
760 Info(slide, 0x401, ((char *)slide,
761 LoadFarStringSmall2(WrnStorUCSizCSizDiff),
762 --
763 2.5.2
764
765 From: Giovanni Scafora <giovanni.archlinux.org>
766 Subject: unzip files encoded with non-latin, non-unicode file names
767 Last-Update: 2015-02-11
768
769 Updated 2015-02-11 by Marc Deslauriers <marc.deslauriers@canonical.com>
770 to fix buffer overflow in charset_to_intern()
771
772 Index: unzip-6.0/unix/unix.c
773 ===================================================================
774 --- unzip-6.0.orig/unix/unix.c 2015-02-11 08:46:43.675324290 -0500
775 +++ unzip-6.0/unix/unix.c 2015-02-11 09:18:04.902081319 -0500
776 @@ -30,6 +30,9 @@
777 #define UNZIP_INTERNAL
778 #include "unzip.h"
779
780 +#include <iconv.h>
781 +#include <langinfo.h>
782 +
783 #ifdef SCO_XENIX
784 # define SYSNDIR
785 #else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
786 @@ -1874,3 +1877,102 @@
787 }
788 }
789 #endif /* QLZIP */
790 +
791 +
792 +typedef struct {
793 + char *local_charset;
794 + char *archive_charset;
795 +} CHARSET_MAP;
796 +
797 +/* A mapping of local <-> archive charsets used by default to convert filenames
798 + * of DOS/Windows Zip archives. Currently very basic. */
799 +static CHARSET_MAP dos_charset_map[] = {
800 + { "ANSI_X3.4-1968", "CP850" },
801 + { "ISO-8859-1", "CP850" },
802 + { "CP1252", "CP850" },
803 + { "UTF-8", "CP866" },
804 + { "KOI8-R", "CP866" },
805 + { "KOI8-U", "CP866" },
806 + { "ISO-8859-5", "CP866" }
807 +};
808 +
809 +char OEM_CP[MAX_CP_NAME] = "";
810 +char ISO_CP[MAX_CP_NAME] = "";
811 +
812 +/* Try to guess the default value of OEM_CP based on the current locale.
813 + * ISO_CP is left alone for now. */
814 +void init_conversion_charsets()
815 +{
816 + const char *local_charset;
817 + int i;
818 +
819 + /* Make a guess only if OEM_CP not already set. */
820 + if(*OEM_CP == '\0') {
821 + local_charset = nl_langinfo(CODESET);
822 + for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++)
823 + if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) {
824 + strncpy(OEM_CP, dos_charset_map[i].archive_charset,
825 + sizeof(OEM_CP));
826 + break;
827 + }
828 + }
829 +}
830 +
831 +/* Convert a string from one encoding to the current locale using iconv().
832 + * Be as non-intrusive as possible. If error is encountered during covertion
833 + * just leave the string intact. */
834 +static void charset_to_intern(char *string, char *from_charset)
835 +{
836 + iconv_t cd;
837 + char *s,*d, *buf;
838 + size_t slen, dlen, buflen;
839 + const char *local_charset;
840 +
841 + if(*from_charset == '\0')
842 + return;
843 +
844 + buf = NULL;
845 + local_charset = nl_langinfo(CODESET);
846 +
847 + if((cd = iconv_open(local_charset, from_charset)) == (iconv_t)-1)
848 + return;
849 +
850 + slen = strlen(string);
851 + s = string;
852 +
853 + /* Make sure OUTBUFSIZ + 1 never ends up smaller than FILNAMSIZ
854 + * as this function also gets called with G.outbuf in fileio.c
855 + */
856 + buflen = FILNAMSIZ;
857 + if (OUTBUFSIZ + 1 < FILNAMSIZ)
858 + {
859 + buflen = OUTBUFSIZ + 1;
860 + }
861 +
862 + d = buf = malloc(buflen);
863 + if(!d)
864 + goto cleanup;
865 +
866 + bzero(buf,buflen);
867 + dlen = buflen - 1;
868 +
869 + if(iconv(cd, &s, &slen, &d, &dlen) == (size_t)-1)
870 + goto cleanup;
871 + strncpy(string, buf, buflen);
872 +
873 + cleanup:
874 + free(buf);
875 + iconv_close(cd);
876 +}
877 +
878 +/* Convert a string from OEM_CP to the current locale charset. */
879 +inline void oem_intern(char *string)
880 +{
881 + charset_to_intern(string, OEM_CP);
882 +}
883 +
884 +/* Convert a string from ISO_CP to the current locale charset. */
885 +inline void iso_intern(char *string)
886 +{
887 + charset_to_intern(string, ISO_CP);
888 +}
889 Index: unzip-6.0/unix/unxcfg.h
890 ===================================================================
891 --- unzip-6.0.orig/unix/unxcfg.h 2015-02-11 08:46:43.675324290 -0500
892 +++ unzip-6.0/unix/unxcfg.h 2015-02-11 08:46:43.671324260 -0500
893 @@ -228,4 +228,30 @@
894 /* wild_dir, dirname, wildname, matchname[], dirnamelen, have_dirname, */
895 /* and notfirstcall are used by do_wild(). */
896
897 +
898 +#define MAX_CP_NAME 25
899 +
900 +#ifdef SETLOCALE
901 +# undef SETLOCALE
902 +#endif
903 +#define SETLOCALE(category, locale) setlocale(category, locale)
904 +#include <locale.h>
905 +
906 +#ifdef _ISO_INTERN
907 +# undef _ISO_INTERN
908 +#endif
909 +#define _ISO_INTERN(str1) iso_intern(str1)
910 +
911 +#ifdef _OEM_INTERN
912 +# undef _OEM_INTERN
913 +#endif
914 +#ifndef IZ_OEM2ISO_ARRAY
915 +# define IZ_OEM2ISO_ARRAY
916 +#endif
917 +#define _OEM_INTERN(str1) oem_intern(str1)
918 +
919 +void iso_intern(char *);
920 +void oem_intern(char *);
921 +void init_conversion_charsets(void);
922 +
923 #endif /* !__unxcfg_h */
924 Index: unzip-6.0/unzip.c
925 ===================================================================
926 --- unzip-6.0.orig/unzip.c 2015-02-11 08:46:43.675324290 -0500
927 +++ unzip-6.0/unzip.c 2015-02-11 08:46:43.675324290 -0500
928 @@ -327,11 +327,21 @@
929 -2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\
930 -v verbose, multi-page format\n";
931
932 +#ifndef UNIX
933 static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
934 -h print header line -t print totals for listed files or for all\n\
935 -z print zipfile comment -T print file times in sortable decimal format\
936 \n -C be case-insensitive %s\
937 -x exclude filenames that follow from listing\n";
938 +#else /* UNIX */
939 +static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
940 + -h print header line -t print totals for listed files or for all\n\
941 + -z print zipfile comment %c-T%c print file times in sortable decimal format\
942 +\n %c-C%c be case-insensitive %s\
943 + -x exclude filenames that follow from listing\n\
944 + -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
945 + -I CHARSET specify a character encoding for UNIX and other archives\n";
946 +#endif /* !UNIX */
947 #ifdef MORE
948 static ZCONST char Far ZipInfoUsageLine4[] =
949 " -M page output through built-in \"more\"\n";
950 @@ -664,6 +674,17 @@
951 -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
952 -C match filenames case-insensitively -L make (some) names \
953 lowercase\n %-42s -V retain VMS version numbers\n%s";
954 +#elif (defined UNIX)
955 +static ZCONST char Far UnzipUsageLine4[] = "\
956 +modifiers:\n\
957 + -n never overwrite existing files -q quiet mode (-qq => quieter)\n\
958 + -o overwrite files WITHOUT prompting -a auto-convert any text files\n\
959 + -j junk paths (do not make directories) -aa treat ALL files as text\n\
960 + -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
961 + -C match filenames case-insensitively -L make (some) names \
962 +lowercase\n %-42s -V retain VMS version numbers\n%s\
963 + -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
964 + -I CHARSET specify a character encoding for UNIX and other archives\n\n";
965 #else /* !VMS */
966 static ZCONST char Far UnzipUsageLine4[] = "\
967 modifiers:\n\
968 @@ -802,6 +823,10 @@
969 #endif /* UNICODE_SUPPORT */
970
971
972 +#ifdef UNIX
973 + init_conversion_charsets();
974 +#endif
975 +
976 #if (defined(__IBMC__) && defined(__DEBUG_ALLOC__))
977 extern void DebugMalloc(void);
978
979 @@ -1335,6 +1360,11 @@
980 argc = *pargc;
981 argv = *pargv;
982
983 +#ifdef UNIX
984 + extern char OEM_CP[MAX_CP_NAME];
985 + extern char ISO_CP[MAX_CP_NAME];
986 +#endif
987 +
988 while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
989 s = *argv + 1;
990 while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */
991 @@ -1516,6 +1546,35 @@
992 }
993 break;
994 #endif /* MACOS */
995 +#ifdef UNIX
996 + case ('I'):
997 + if (negative) {
998 + Info(slide, 0x401, ((char *)slide,
999 + "error: encodings can't be negated"));
1000 + return(PK_PARAM);
1001 + } else {
1002 + if(*s) { /* Handle the -Icharset case */
1003 + /* Assume that charsets can't start with a dash to spot arguments misuse */
1004 + if(*s == '-') {
1005 + Info(slide, 0x401, ((char *)slide,
1006 + "error: a valid character encoding should follow the -I argument"));
1007 + return(PK_PARAM);
1008 + }
1009 + strncpy(ISO_CP, s, sizeof(ISO_CP));
1010 + } else { /* -I charset */
1011 + ++argv;
1012 + if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
1013 + Info(slide, 0x401, ((char *)slide,
1014 + "error: a valid character encoding should follow the -I argument"));
1015 + return(PK_PARAM);
1016 + }
1017 + s = *argv;
1018 + strncpy(ISO_CP, s, sizeof(ISO_CP));
1019 + }
1020 + while(*(++s)); /* No params straight after charset name */
1021 + }
1022 + break;
1023 +#endif /* ?UNIX */
1024 case ('j'): /* junk pathnames/directory structure */
1025 if (negative)
1026 uO.jflag = FALSE, negative = 0;
1027 @@ -1591,6 +1650,35 @@
1028 } else
1029 ++uO.overwrite_all;
1030 break;
1031 +#ifdef UNIX
1032 + case ('O'):
1033 + if (negative) {
1034 + Info(slide, 0x401, ((char *)slide,
1035 + "error: encodings can't be negated"));
1036 + return(PK_PARAM);
1037 + } else {
1038 + if(*s) { /* Handle the -Ocharset case */
1039 + /* Assume that charsets can't start with a dash to spot arguments misuse */
1040 + if(*s == '-') {
1041 + Info(slide, 0x401, ((char *)slide,
1042 + "error: a valid character encoding should follow the -I argument"));
1043 + return(PK_PARAM);
1044 + }
1045 + strncpy(OEM_CP, s, sizeof(OEM_CP));
1046 + } else { /* -O charset */
1047 + ++argv;
1048 + if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
1049 + Info(slide, 0x401, ((char *)slide,
1050 + "error: a valid character encoding should follow the -O argument"));
1051 + return(PK_PARAM);
1052 + }
1053 + s = *argv;
1054 + strncpy(OEM_CP, s, sizeof(OEM_CP));
1055 + }
1056 + while(*(++s)); /* No params straight after charset name */
1057 + }
1058 + break;
1059 +#endif /* ?UNIX */
1060 case ('p'): /* pipes: extract to stdout, no messages */
1061 if (negative) {
1062 uO.cflag = FALSE;
1063 Index: unzip-6.0/unzpriv.h
1064 ===================================================================
1065 --- unzip-6.0.orig/unzpriv.h 2015-02-11 08:46:43.675324290 -0500
1066 +++ unzip-6.0/unzpriv.h 2015-02-11 08:46:43.675324290 -0500
1067 @@ -3008,7 +3008,7 @@
1068 !(((islochdr) || (isuxatt)) && \
1069 ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
1070 (hostnum) == FS_HPFS_ || \
1071 - ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
1072 + ((hostnum) == FS_NTFS_ /* && (hostver) == 50 */ )) { \
1073 _OEM_INTERN((string)); \
1074 } else { \
1075 _ISO_INTERN((string)); \
1076 Index: unzip-6.0/zipinfo.c
1077 ===================================================================
1078 --- unzip-6.0.orig/zipinfo.c 2015-02-11 08:46:43.675324290 -0500
1079 +++ unzip-6.0/zipinfo.c 2015-02-11 08:46:43.675324290 -0500
1080 @@ -457,6 +457,10 @@
1081 int tflag_slm=TRUE, tflag_2v=FALSE;
1082 int explicit_h=FALSE, explicit_t=FALSE;
1083
1084 +#ifdef UNIX
1085 + extern char OEM_CP[MAX_CP_NAME];
1086 + extern char ISO_CP[MAX_CP_NAME];
1087 +#endif
1088
1089 #ifdef MACOS
1090 uO.lflag = LFLAG; /* reset default on each call */
1091 @@ -501,6 +505,35 @@
1092 uO.lflag = 0;
1093 }
1094 break;
1095 +#ifdef UNIX
1096 + case ('I'):
1097 + if (negative) {
1098 + Info(slide, 0x401, ((char *)slide,
1099 + "error: encodings can't be negated"));
1100 + return(PK_PARAM);
1101 + } else {
1102 + if(*s) { /* Handle the -Icharset case */
1103 + /* Assume that charsets can't start with a dash to spot arguments misuse */
1104 + if(*s == '-') {
1105 + Info(slide, 0x401, ((char *)slide,
1106 + "error: a valid character encoding should follow the -I argument"));
1107 + return(PK_PARAM);
1108 + }
1109 + strncpy(ISO_CP, s, sizeof(ISO_CP));
1110 + } else { /* -I charset */
1111 + ++argv;
1112 + if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
1113 + Info(slide, 0x401, ((char *)slide,
1114 + "error: a valid character encoding should follow the -I argument"));
1115 + return(PK_PARAM);
1116 + }
1117 + s = *argv;
1118 + strncpy(ISO_CP, s, sizeof(ISO_CP));
1119 + }
1120 + while(*(++s)); /* No params straight after charset name */
1121 + }
1122 + break;
1123 +#endif /* ?UNIX */
1124 case 'l': /* longer form of "ls -l" type listing */
1125 if (negative)
1126 uO.lflag = -2, negative = 0;
1127 @@ -521,6 +554,35 @@
1128 G.M_flag = TRUE;
1129 break;
1130 #endif
1131 +#ifdef UNIX
1132 + case ('O'):
1133 + if (negative) {
1134 + Info(slide, 0x401, ((char *)slide,
1135 + "error: encodings can't be negated"));
1136 + return(PK_PARAM);
1137 + } else {
1138 + if(*s) { /* Handle the -Ocharset case */
1139 + /* Assume that charsets can't start with a dash to spot arguments misuse */
1140 + if(*s == '-') {
1141 + Info(slide, 0x401, ((char *)slide,
1142 + "error: a valid character encoding should follow the -I argument"));
1143 + return(PK_PARAM);
1144 + }
1145 + strncpy(OEM_CP, s, sizeof(OEM_CP));
1146 + } else { /* -O charset */
1147 + ++argv;
1148 + if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
1149 + Info(slide, 0x401, ((char *)slide,
1150 + "error: a valid character encoding should follow the -O argument"));
1151 + return(PK_PARAM);
1152 + }
1153 + s = *argv;
1154 + strncpy(OEM_CP, s, sizeof(OEM_CP));
1155 + }
1156 + while(*(++s)); /* No params straight after charset name */
1157 + }
1158 + break;
1159 +#endif /* ?UNIX */
1160 case 's': /* default: shorter "ls -l" type listing */
1161 if (negative)
1162 uO.lflag = -2, negative = 0;
1163 From ca0212ba19b64488b9e8459a762c11ecd6e7d0bd Mon Sep 17 00:00:00 2001
1164 From: Petr Stodulka <pstodulk@redhat.com>
1165 Date: Tue, 24 Nov 2015 17:56:11 +0100
1166 Subject: [PATCH] print correctly non-ascii filenames
1167
1168 ---
1169 extract.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++--------------
1170 unzpriv.h | 7 ++
1171 2 files changed, 233 insertions(+), 63 deletions(-)
1172
1173 diff --git a/extract.c b/extract.c
1174 index 0ee4e93..741b7e0 100644
1175 --- a/extract.c
1176 +++ b/extract.c
1177 @@ -2648,8 +2648,21 @@ static void set_deferred_symlink(__G__ slnk_entry)
1178 } /* end function set_deferred_symlink() */
1179 #endif /* SYMLINKS */
1180
1181 +/*
1182 + * If Unicode is supported, assume we have what we need to do this
1183 + * check using wide characters, avoiding MBCS issues.
1184 + */
1185
1186 -
1187 +#ifndef UZ_FNFILTER_REPLACECHAR
1188 + /* A convenient choice for the replacement of unprintable char codes is
1189 + * the "single char wildcard", as this character is quite unlikely to
1190 + * appear in filenames by itself. The following default definition
1191 + * sets the replacement char to a question mark as the most common
1192 + * "single char wildcard"; this setting should be overridden in the
1193 + * appropiate system-specific configuration header when needed.
1194 + */
1195 +# define UZ_FNFILTER_REPLACECHAR '?'
1196 +#endif
1197
1198 /*************************/
1199 /* Function fnfilter() */ /* here instead of in list.c for SFX */
1200 @@ -2661,48 +2674,168 @@ char *fnfilter(raw, space, size) /* convert name to safely printable form */
1201 extent size;
1202 {
1203 #ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */
1204 - ZCONST uch *r=(ZCONST uch *)raw;
1205 + ZCONST uch *r; // =(ZCONST uch *)raw;
1206 uch *s=space;
1207 uch *slim=NULL;
1208 uch *se=NULL;
1209 int have_overflow = FALSE;
1210
1211 - if (size > 0) {
1212 - slim = space + size
1213 -#ifdef _MBCS
1214 - - (MB_CUR_MAX - 1)
1215 -#endif
1216 - - 4;
1217 +# if defined( UNICODE_SUPPORT) && defined( _MBCS)
1218 +/* If Unicode support is enabled, and we have multi-byte characters,
1219 + * then do the isprint() checks by first converting to wide characters
1220 + * and checking those. This avoids our having to parse multi-byte
1221 + * characters for ourselves. After the wide-char replacements have been
1222 + * made, the wide string is converted back to the local character set.
1223 + */
1224 + wchar_t *wstring; /* wchar_t version of raw */
1225 + size_t wslen; /* length of wstring */
1226 + wchar_t *wostring; /* wchar_t version of output string */
1227 + size_t woslen; /* length of wostring */
1228 + char *newraw; /* new raw */
1229 +
1230 + /* 2012-11-06 SMS.
1231 + * Changed to check the value returned by mbstowcs(), and bypass the
1232 + * Unicode processing if it fails. This seems to fix a problem
1233 + * reported in the SourceForge forum, but it's not clear that we
1234 + * should be doing any Unicode processing without some evidence that
1235 + * the name actually is Unicode. (Check bit 11 in the flags before
1236 + * coming here?)
1237 + * http://sourceforge.net/p/infozip/bugs/40/
1238 + */
1239 +
1240 + if (MB_CUR_MAX <= 1)
1241 + {
1242 + /* There's no point to converting multi-byte chars if there are
1243 + * no multi-byte chars.
1244 + */
1245 + wslen = (size_t)-1;
1246 }
1247 - while (*r) {
1248 - if (size > 0 && s >= slim && se == NULL) {
1249 - se = s;
1250 + else
1251 + {
1252 + /* Get Unicode wide character count (for storage allocation). */
1253 + wslen = mbstowcs( NULL, raw, 0);
1254 + }
1255 +
1256 + if (wslen != (size_t)-1)
1257 + {
1258 + /* Apparently valid Unicode. Allocate wide-char storage. */
1259 + wstring = (wchar_t *)malloc((wslen + 1) * sizeof(wchar_t));
1260 + if (wstring == NULL) {
1261 + strcpy( (char *)space, raw);
1262 + return (char *)space;
1263 }
1264 -#ifdef QDOS
1265 - if (qlflag & 2) {
1266 - if (*r == '/' || *r == '.') {
1267 + wostring = (wchar_t *)malloc(2 * (wslen + 1) * sizeof(wchar_t));
1268 + if (wostring == NULL) {
1269 + free(wstring);
1270 + strcpy( (char *)space, raw);
1271 + return (char *)space;
1272 + }
1273 +
1274 + /* Convert the multi-byte Unicode to wide chars. */
1275 + wslen = mbstowcs(wstring, raw, wslen + 1);
1276 +
1277 + /* Filter the wide-character string. */
1278 + fnfilterw( wstring, wostring, (2 * (wslen + 1) * sizeof(wchar_t)));
1279 +
1280 + /* Convert filtered wide chars back to multi-byte. */
1281 + woslen = wcstombs( NULL, wostring, 0);
1282 + if ((newraw = malloc(woslen + 1)) == NULL) {
1283 + free(wstring);
1284 + free(wostring);
1285 + strcpy( (char *)space, raw);
1286 + return (char *)space;
1287 + }
1288 + woslen = wcstombs( newraw, wostring, (woslen * MB_CUR_MAX) + 1);
1289 +
1290 + if (size > 0) {
1291 + slim = space + size - 4;
1292 + }
1293 + r = (ZCONST uch *)newraw;
1294 + while (*r) {
1295 + if (size > 0 && s >= slim && se == NULL) {
1296 + se = s;
1297 + }
1298 +# ifdef QDOS
1299 + if (qlflag & 2) {
1300 + if (*r == '/' || *r == '.') {
1301 + if (se != NULL && (s > (space + (size-3)))) {
1302 + have_overflow = TRUE;
1303 + break;
1304 + }
1305 + ++r;
1306 + *s++ = '_';
1307 + continue;
1308 + }
1309 + } else
1310 +# endif
1311 + {
1312 if (se != NULL && (s > (space + (size-3)))) {
1313 have_overflow = TRUE;
1314 break;
1315 }
1316 - ++r;
1317 - *s++ = '_';
1318 - continue;
1319 + *s++ = *r++;
1320 }
1321 - } else
1322 + }
1323 + if (have_overflow) {
1324 + strcpy((char *)se, "...");
1325 + } else {
1326 + *s = '\0';
1327 + }
1328 +
1329 + free(wstring);
1330 + free(wostring);
1331 + free(newraw);
1332 + }
1333 + else
1334 +# endif /* defined( UNICODE_SUPPORT) && defined( _MBCS) */
1335 + {
1336 + /* No Unicode support, or apparently invalid Unicode. */
1337 + r = (ZCONST uch *)raw;
1338 +
1339 + if (size > 0) {
1340 + slim = space + size
1341 +#ifdef _MBCS
1342 + - (MB_CUR_MAX - 1)
1343 +#endif
1344 + - 4;
1345 + }
1346 + while (*r) {
1347 + if (size > 0 && s >= slim && se == NULL) {
1348 + se = s;
1349 + }
1350 +#ifdef QDOS
1351 + if (qlflag & 2) {
1352 + if (*r == '/' || *r == '.') {
1353 + if (se != NULL && (s > (space + (size-3)))) {
1354 + have_overflow = TRUE;
1355 + break;
1356 + }
1357 + ++r;
1358 + *s++ = '_';
1359 + continue;
1360 + }
1361 + } else
1362 #endif
1363 #ifdef HAVE_WORKING_ISPRINT
1364 -# ifndef UZ_FNFILTER_REPLACECHAR
1365 - /* A convenient choice for the replacement of unprintable char codes is
1366 - * the "single char wildcard", as this character is quite unlikely to
1367 - * appear in filenames by itself. The following default definition
1368 - * sets the replacement char to a question mark as the most common
1369 - * "single char wildcard"; this setting should be overridden in the
1370 - * appropiate system-specific configuration header when needed.
1371 - */
1372 -# define UZ_FNFILTER_REPLACECHAR '?'
1373 -# endif
1374 - if (!isprint(*r)) {
1375 + if (!isprint(*r)) {
1376 + if (*r < 32) {
1377 + /* ASCII control codes are escaped as "^{letter}". */
1378 + if (se != NULL && (s > (space + (size-4)))) {
1379 + have_overflow = TRUE;
1380 + break;
1381 + }
1382 + *s++ = '^', *s++ = (uch)(64 + *r++);
1383 + } else {
1384 + /* Other unprintable codes are replaced by the
1385 + * placeholder character. */
1386 + if (se != NULL && (s > (space + (size-3)))) {
1387 + have_overflow = TRUE;
1388 + break;
1389 + }
1390 + *s++ = UZ_FNFILTER_REPLACECHAR;
1391 + INCSTR(r);
1392 + }
1393 +#else /* !HAVE_WORKING_ISPRINT */
1394 if (*r < 32) {
1395 /* ASCII control codes are escaped as "^{letter}". */
1396 if (se != NULL && (s > (space + (size-4)))) {
1397 @@ -2710,47 +2843,30 @@ char *fnfilter(raw, space, size) /* convert name to safely printable form */
1398 break;
1399 }
1400 *s++ = '^', *s++ = (uch)(64 + *r++);
1401 +#endif /* ?HAVE_WORKING_ISPRINT */
1402 } else {
1403 - /* Other unprintable codes are replaced by the
1404 - * placeholder character. */
1405 +#ifdef _MBCS
1406 + unsigned i = CLEN(r);
1407 + if (se != NULL && (s > (space + (size-i-2)))) {
1408 + have_overflow = TRUE;
1409 + break;
1410 + }
1411 + for (; i > 0; i--)
1412 + *s++ = *r++;
1413 +#else
1414 if (se != NULL && (s > (space + (size-3)))) {
1415 have_overflow = TRUE;
1416 break;
1417 }
1418 - *s++ = UZ_FNFILTER_REPLACECHAR;
1419 - INCSTR(r);
1420 - }
1421 -#else /* !HAVE_WORKING_ISPRINT */
1422 - if (*r < 32) {
1423 - /* ASCII control codes are escaped as "^{letter}". */
1424 - if (se != NULL && (s > (space + (size-4)))) {
1425 - have_overflow = TRUE;
1426 - break;
1427 - }
1428 - *s++ = '^', *s++ = (uch)(64 + *r++);
1429 -#endif /* ?HAVE_WORKING_ISPRINT */
1430 - } else {
1431 -#ifdef _MBCS
1432 - unsigned i = CLEN(r);
1433 - if (se != NULL && (s > (space + (size-i-2)))) {
1434 - have_overflow = TRUE;
1435 - break;
1436 - }
1437 - for (; i > 0; i--)
1438 *s++ = *r++;
1439 -#else
1440 - if (se != NULL && (s > (space + (size-3)))) {
1441 - have_overflow = TRUE;
1442 - break;
1443 - }
1444 - *s++ = *r++;
1445 #endif
1446 - }
1447 - }
1448 - if (have_overflow) {
1449 - strcpy((char *)se, "...");
1450 - } else {
1451 - *s = '\0';
1452 + }
1453 + }
1454 + if (have_overflow) {
1455 + strcpy((char *)se, "...");
1456 + } else {
1457 + *s = '\0';
1458 + }
1459 }
1460
1461 #ifdef WINDLL
1462 @@ -2772,6 +2888,53 @@ char *fnfilter(raw, space, size) /* convert name to safely printable form */
1463 } /* end function fnfilter() */
1464
1465
1466 +#if defined( UNICODE_SUPPORT) && defined( _MBCS)
1467 +
1468 +/****************************/
1469 +/* Function fnfilter[w]() */ /* (Here instead of in list.c for SFX.) */
1470 +/****************************/
1471 +
1472 +/* fnfilterw() - Convert wide name to safely printable form. */
1473 +
1474 +/* fnfilterw() - Convert wide-character name to safely printable form. */
1475 +
1476 +wchar_t *fnfilterw( src, dst, siz)
1477 + ZCONST wchar_t *src; /* Pointer to source char (string). */
1478 + wchar_t *dst; /* Pointer to destination char (string). */
1479 + extent siz; /* Not used (!). */
1480 +{
1481 + wchar_t *dsx = dst;
1482 +
1483 + /* Filter the wide chars. */
1484 + while (*src)
1485 + {
1486 + if (iswprint( *src))
1487 + {
1488 + /* Printable code. Copy it. */
1489 + *dst++ = *src;
1490 + }
1491 + else
1492 + {
1493 + /* Unprintable code. Substitute something printable for it. */
1494 + if (*src < 32)
1495 + {
1496 + /* Replace ASCII control code with "^{letter}". */
1497 + *dst++ = (wchar_t)'^';
1498 + *dst++ = (wchar_t)(64 + *src);
1499 + }
1500 + else
1501 + {
1502 + /* Replace other unprintable code with the placeholder. */
1503 + *dst++ = (wchar_t)UZ_FNFILTER_REPLACECHAR;
1504 + }
1505 + }
1506 + src++;
1507 + }
1508 + *dst = (wchar_t)0; /* NUL-terminate the destination string. */
1509 + return dsx;
1510 +} /* fnfilterw(). */
1511 +
1512 +#endif /* defined( UNICODE_SUPPORT) && defined( _MBCS) */
1513
1514
1515 #ifdef SET_DIR_ATTRIB
1516 diff --git a/unzpriv.h b/unzpriv.h
1517 index 22d3923..e48a652 100644
1518 --- a/unzpriv.h
1519 +++ b/unzpriv.h
1520 @@ -1212,6 +1212,7 @@
1521 # ifdef UNICODE_WCHAR
1522 # if !(defined(_WIN32_WCE) || defined(POCKET_UNZIP))
1523 # include <wchar.h>
1524 +# include <wctype.h>
1525 # endif
1526 # endif
1527 # ifndef _MBCS /* no need to include <locale.h> twice, see below */
1528 @@ -2410,6 +2411,12 @@ int memflush OF((__GPRO__ ZCONST uch *rawbuf, ulg size));
1529 char *fnfilter OF((ZCONST char *raw, uch *space,
1530 extent size));
1531
1532 +# if defined( UNICODE_SUPPORT) && defined( _MBCS)
1533 +wchar_t *fnfilterw OF((ZCONST wchar_t *src, wchar_t *dst,
1534 + extent siz));
1535 +#endif
1536 +
1537 +
1538 /*---------------------------------------------------------------------------
1539 Decompression functions:
1540 ---------------------------------------------------------------------------*/
1541 --
1542 2.4.3
1543
1544 From 754137e70cf58a64ad524b704a86b651ba0cde07 Mon Sep 17 00:00:00 2001
1545 From: Petr Stodulka <pstodulk@redhat.com>
1546 Date: Wed, 14 Dec 2016 16:30:36 +0100
1547 Subject: [PATCH] Fix CVE-2016-9844 (rhbz#1404283)
1548
1549 Fixes buffer overflow in zipinfo in similar way like fix for
1550 CVE-2014-9913 provided by upstream.
1551 ---
1552 zipinfo.c | 14 +++++++++++++-
1553 1 file changed, 13 insertions(+), 1 deletion(-)
1554
1555 diff --git a/zipinfo.c b/zipinfo.c
1556 index c03620e..accca2a 100644
1557 --- a/zipinfo.c
1558 +++ b/zipinfo.c
1559 @@ -1984,7 +1984,19 @@ static int zi_short(__G) /* return PK-type error code */
1560 ush dnum=(ush)((G.crec.general_purpose_bit_flag>>1) & 3);
1561 methbuf[3] = dtype[dnum];
1562 } else if (methnum >= NUM_METHODS) { /* unknown */
1563 - sprintf(&methbuf[1], "%03u", G.crec.compression_method);
1564 + /* 2016-12-05 SMS.
1565 + * https://launchpad.net/bugs/1643750
1566 + * Unexpectedly large compression methods overflow
1567 + * &methbuf[]. Use the old, three-digit decimal format
1568 + * for values which fit. Otherwise, sacrifice the "u",
1569 + * and use four-digit hexadecimal.
1570 + */
1571 + if (G.crec.compression_method <= 999) {
1572 + sprintf( &methbuf[ 1], "%03u", G.crec.compression_method);
1573 + } else {
1574 + sprintf( &methbuf[ 0], "%04X", G.crec.compression_method);
1575 + }
1576 +
1577 }
1578
1579 for (k = 0; k < 15; ++k)
1580 --
1581 2.5.5
1582
1583 From: "Steven M. Schweda" <sms@antinode.info>
1584 Subject: Do not ignore extra fields containing Unix Timestamps
1585 Bug-Debian: https://bugs.debian.org/842993
1586 X-Debian-version: 6.0-21
1587
1588 --- a/process.c
1589 +++ b/process.c
1590 @@ -2914,10 +2914,13 @@
1591 break;
1592
1593 case EF_IZUNIX2:
1594 - if (have_new_type_eb == 0) {
1595 - flags &= ~0x0ff; /* ignore any previous IZUNIX field */
1596 + if (have_new_type_eb == 0) { /* (< 1) */
1597 have_new_type_eb = 1;
1598 }
1599 + if (have_new_type_eb <= 1) {
1600 + /* Ignore any prior (EF_IZUNIX/EF_PKUNIX) UID/GID. */
1601 + flags &= 0x0ff;
1602 + }
1603 #ifdef IZ_HAVE_UXUIDGID
1604 if (have_new_type_eb > 1)
1605 break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */
1606 @@ -2933,6 +2936,8 @@
1607 /* new 3rd generation Unix ef */
1608 have_new_type_eb = 2;
1609
1610 + /* Ignore any prior EF_IZUNIX/EF_PKUNIX/EF_IZUNIX2 UID/GID. */
1611 + flags &= 0x0ff;
1612 /*
1613 Version 1 byte version of this extra field, currently 1
1614 UIDSize 1 byte Size of UID field
1615 @@ -2953,8 +2958,6 @@
1616 uid_size = *((EB_HEADSIZE + 1) + ef_buf);
1617 gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf);
1618
1619 - flags &= ~0x0ff; /* ignore any previous UNIX field */
1620 -
1621 if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf,
1622 uid_size, &z_uidgid[0])
1623 &&
1624 --- a/fileio.c 2014-12-05 05:06:05 -0600
1625 +++ b/fileio.c 2017-11-14 01:06:28 -0600
1626 @@ -1,5 +1,5 @@
1627 /*
1628 - Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
1629 + Copyright (c) 1990-2017 Info-ZIP. All rights reserved.
1630
1631 See the accompanying file LICENSE, version 2009-Jan-02 or later
1632 (the contents of which are also included in unzip.h) for terms of use.
1633 @@ -1582,6 +1582,8 @@
1634 int r = IZ_PW_ENTERED;
1635 char *m;
1636 char *prompt;
1637 + char *ep;
1638 + char *zp;
1639
1640 #ifndef REENTRANT
1641 /* tell picky compilers to shut up about "unused variable" warnings */
1642 @@ -1590,9 +1592,12 @@
1643
1644 if (*rcnt == 0) { /* First call for current entry */
1645 *rcnt = 2;
1646 - if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) {
1647 - sprintf(prompt, LoadFarString(PasswPrompt),
1648 - FnFilter1(zfn), FnFilter2(efn));
1649 + zp = FnFilter1( zfn);
1650 + ep = FnFilter2( efn);
1651 + prompt = (char *)malloc( /* Slightly too long (2* "%s"). */
1652 + sizeof( PasswPrompt)+ strlen( zp)+ strlen( ep));
1653 + if (prompt != (char *)NULL) {
1654 + sprintf(prompt, LoadFarString(PasswPrompt), zp, ep);
1655 m = prompt;
1656 } else
1657 m = (char *)LoadFarString(PasswPrompt2);
1658 --- unzip60/list.c
1659 +++ unzip60/list.c
1660 @@ -97,7 +97,7 @@ int list_files(__G) /* return PK-type
1661 {
1662 int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
1663 #ifndef WINDLL
1664 - char sgn, cfactorstr[13];
1665 + char sgn, cfactorstr[1+10+1+1]; /* <sgn><int>%NUL */
1666 int longhdr=(uO.vflag>1);
1667 #endif
1668 int date_format;
1669 @@ -389,9 +389,9 @@ int list_files(__G) /* return PK-type
1670 }
1671 #else /* !WINDLL */
1672 if (cfactor == 100)
1673 - sprintf(cfactorstr, LoadFarString(CompFactor100));
1674 + snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100));
1675 else
1676 - sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
1677 + snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor);
1678 if (longhdr)
1679 Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats),
1680 FmZofft(G.crec.ucsize, "8", "u"), methbuf,
1681 @@ -471,9 +471,9 @@ int list_files(__G) /* return PK-type
1682
1683 #else /* !WINDLL */
1684 if (cfactor == 100)
1685 - sprintf(cfactorstr, LoadFarString(CompFactor100));
1686 + snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100));
1687 else
1688 - sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
1689 + snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor);
1690 if (longhdr) {
1691 Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer),
1692 FmZofft(tot_ucsize, "8", "u"), FmZofft(tot_csize, "8", "u"),
1693 From 06d1b08aef94984256cad3c5a54cedb10295681f Mon Sep 17 00:00:00 2001
1694 From: Jakub Martisko <jamartis@redhat.com>
1695 Date: Thu, 8 Nov 2018 09:31:18 +0100
1696 Subject: [PATCH] Possible unterminated string fix
1697
1698 ---
1699 unix/unix.c | 4 +++-
1700 unix/unxcfg.h | 2 +-
1701 unzip.c | 12 ++++++++----
1702 zipinfo.c | 12 ++++++++----
1703 4 files changed, 20 insertions(+), 10 deletions(-)
1704
1705 diff --git a/unix/unix.c b/unix/unix.c
1706 index 59b622d..cd57f80 100644
1707 --- a/unix/unix.c
1708 +++ b/unix/unix.c
1709 @@ -1945,7 +1945,9 @@ void init_conversion_charsets()
1710 for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++)
1711 if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) {
1712 strncpy(OEM_CP, dos_charset_map[i].archive_charset,
1713 - sizeof(OEM_CP));
1714 + MAX_CP_NAME - 1);
1715 +
1716 + OEM_CP[MAX_CP_NAME - 1] = '\0';
1717 break;
1718 }
1719 }
1720 diff --git a/unix/unxcfg.h b/unix/unxcfg.h
1721 index 8729de2..9ee8cfe 100644
1722 --- a/unix/unxcfg.h
1723 +++ b/unix/unxcfg.h
1724 @@ -228,7 +228,7 @@ typedef struct stat z_stat;
1725 /* and notfirstcall are used by do_wild(). */
1726
1727
1728 -#define MAX_CP_NAME 25
1729 +#define MAX_CP_NAME 25 + 1
1730
1731 #ifdef SETLOCALE
1732 # undef SETLOCALE
1733 diff --git a/unzip.c b/unzip.c
1734 index 2d94a38..a485f2b 100644
1735 --- a/unzip.c
1736 +++ b/unzip.c
1737 @@ -1561,7 +1561,8 @@ int uz_opts(__G__ pargc, pargv)
1738 "error: a valid character encoding should follow the -I argument"));
1739 return(PK_PARAM);
1740 }
1741 - strncpy(ISO_CP, s, sizeof(ISO_CP));
1742 + strncpy(ISO_CP, s, MAX_CP_NAME - 1);
1743 + ISO_CP[MAX_CP_NAME - 1] = '\0';
1744 } else { /* -I charset */
1745 ++argv;
1746 if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
1747 @@ -1570,7 +1571,8 @@ int uz_opts(__G__ pargc, pargv)
1748 return(PK_PARAM);
1749 }
1750 s = *argv;
1751 - strncpy(ISO_CP, s, sizeof(ISO_CP));
1752 + strncpy(ISO_CP, s, MAX_CP_NAME - 1);
1753 + ISO_CP[MAX_CP_NAME - 1] = '\0';
1754 }
1755 while(*(++s)); /* No params straight after charset name */
1756 }
1757 @@ -1665,7 +1667,8 @@ int uz_opts(__G__ pargc, pargv)
1758 "error: a valid character encoding should follow the -I argument"));
1759 return(PK_PARAM);
1760 }
1761 - strncpy(OEM_CP, s, sizeof(OEM_CP));
1762 + strncpy(OEM_CP, s, MAX_CP_NAME - 1);
1763 + OEM_CP[MAX_CP_NAME - 1] = '\0';
1764 } else { /* -O charset */
1765 ++argv;
1766 if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
1767 @@ -1674,7 +1677,8 @@ int uz_opts(__G__ pargc, pargv)
1768 return(PK_PARAM);
1769 }
1770 s = *argv;
1771 - strncpy(OEM_CP, s, sizeof(OEM_CP));
1772 + strncpy(OEM_CP, s, MAX_CP_NAME - 1);
1773 + OEM_CP[MAX_CP_NAME - 1] = '\0';
1774 }
1775 while(*(++s)); /* No params straight after charset name */
1776 }
1777 diff --git a/zipinfo.c b/zipinfo.c
1778 index accca2a..cb7e08d 100644
1779 --- a/zipinfo.c
1780 +++ b/zipinfo.c
1781 @@ -519,7 +519,8 @@ int zi_opts(__G__ pargc, pargv)
1782 "error: a valid character encoding should follow the -I argument"));
1783 return(PK_PARAM);
1784 }
1785 - strncpy(ISO_CP, s, sizeof(ISO_CP));
1786 + strncpy(ISO_CP, s, MAX_CP_NAME - 1);
1787 + ISO_CP[MAX_CP_NAME - 1] = '\0';
1788 } else { /* -I charset */
1789 ++argv;
1790 if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
1791 @@ -528,7 +529,8 @@ int zi_opts(__G__ pargc, pargv)
1792 return(PK_PARAM);
1793 }
1794 s = *argv;
1795 - strncpy(ISO_CP, s, sizeof(ISO_CP));
1796 + strncpy(ISO_CP, s, MAX_CP_NAME - 1);
1797 + ISO_CP[MAX_CP_NAME - 1] = '\0';
1798 }
1799 while(*(++s)); /* No params straight after charset name */
1800 }
1801 @@ -568,7 +570,8 @@ int zi_opts(__G__ pargc, pargv)
1802 "error: a valid character encoding should follow the -I argument"));
1803 return(PK_PARAM);
1804 }
1805 - strncpy(OEM_CP, s, sizeof(OEM_CP));
1806 + strncpy(OEM_CP, s, MAX_CP_NAME - 1);
1807 + OEM_CP[MAX_CP_NAME - 1] = '\0';
1808 } else { /* -O charset */
1809 ++argv;
1810 if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
1811 @@ -577,7 +580,8 @@ int zi_opts(__G__ pargc, pargv)
1812 return(PK_PARAM);
1813 }
1814 s = *argv;
1815 - strncpy(OEM_CP, s, sizeof(OEM_CP));
1816 + strncpy(OEM_CP, s, MAX_CP_NAME - 1);
1817 + OEM_CP[MAX_CP_NAME - 1] = '\0';
1818 }
1819 while(*(++s)); /* No params straight after charset name */
1820 }
1821 --
1822 2.14.5
1823
1824 From 41beb477c5744bc396fa1162ee0c14218ec12213 Mon Sep 17 00:00:00 2001
1825 From: Mark Adler <madler@alumni.caltech.edu>
1826 Date: Mon, 27 May 2019 08:20:32 -0700
1827 Subject: [PATCH] Fix bug in undefer_input() that misplaced the input state.
1828
1829 ---
1830 fileio.c | 4 +++-
1831 1 file changed, 3 insertions(+), 1 deletion(-)
1832
1833 diff --git a/fileio.c b/fileio.c
1834 index c042987..bc00d74 100644
1835 --- a/fileio.c
1836 +++ b/fileio.c
1837 @@ -530,8 +530,10 @@ void undefer_input(__G)
1838 * This condition was checked when G.incnt_leftover was set > 0 in
1839 * defer_leftover_input(), and it is NOT allowed to touch G.csize
1840 * before calling undefer_input() when (G.incnt_leftover > 0)
1841 - * (single exception: see read_byte()'s "G.csize <= 0" handling) !!
1842 + * (single exception: see readbyte()'s "G.csize <= 0" handling) !!
1843 */
1844 + if (G.csize < 0L)
1845 + G.csize = 0L;
1846 G.incnt = G.incnt_leftover + (int)G.csize;
1847 G.inptr = G.inptr_leftover - (int)G.csize;
1848 G.incnt_leftover = 0;
1849 From 47b3ceae397d21bf822bc2ac73052a4b1daf8e1c Mon Sep 17 00:00:00 2001
1850 From: Mark Adler <madler@alumni.caltech.edu>
1851 Date: Tue, 11 Jun 2019 22:01:18 -0700
1852 Subject: [PATCH] Detect and reject a zip bomb using overlapped entries.
1853
1854 This detects an invalid zip file that has at least one entry that
1855 overlaps with another entry or with the central directory to the
1856 end of the file. A Fifield zip bomb uses overlapped local entries
1857 to vastly increase the potential inflation ratio. Such an invalid
1858 zip file is rejected.
1859
1860 See https://www.bamsoftware.com/hacks/zipbomb/ for David Fifield's
1861 analysis, construction, and examples of such zip bombs.
1862
1863 The detection maintains a list of covered spans of the zip files
1864 so far, where the central directory to the end of the file and any
1865 bytes preceding the first entry at zip file offset zero are
1866 considered covered initially. Then as each entry is decompressed
1867 or tested, it is considered covered. When a new entry is about to
1868 be processed, its initial offset is checked to see if it is
1869 contained by a covered span. If so, the zip file is rejected as
1870 invalid.
1871
1872 This commit depends on a preceding commit: "Fix bug in
1873 undefer_input() that misplaced the input state."
1874 ---
1875 extract.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1876 globals.c | 1 +
1877 globals.h | 3 +
1878 process.c | 11 ++++
1879 unzip.h | 1 +
1880 5 files changed, 205 insertions(+), 1 deletion(-)
1881
1882 diff --git a/extract.c b/extract.c
1883 index 1acd769..0973a33 100644
1884 --- a/extract.c
1885 +++ b/extract.c
1886 @@ -319,6 +319,125 @@ static ZCONST char Far UnsupportedExtraField[] =
1887 "\nerror: unsupported extra-field compression type (%u)--skipping\n";
1888 static ZCONST char Far BadExtraFieldCRC[] =
1889 "error [%s]: bad extra-field CRC %08lx (should be %08lx)\n";
1890 +static ZCONST char Far NotEnoughMemCover[] =
1891 + "error: not enough memory for bomb detection\n";
1892 +static ZCONST char Far OverlappedComponents[] =
1893 + "error: invalid zip file with overlapped components (possible zip bomb)\n";
1894 +
1895 +
1896 +
1897 +
1898 +
1899 +/* A growable list of spans. */
1900 +typedef zoff_t bound_t;
1901 +typedef struct {
1902 + bound_t beg; /* start of the span */
1903 + bound_t end; /* one past the end of the span */
1904 +} span_t;
1905 +typedef struct {
1906 + span_t *span; /* allocated, distinct, and sorted list of spans */
1907 + size_t num; /* number of spans in the list */
1908 + size_t max; /* allocated number of spans (num <= max) */
1909 +} cover_t;
1910 +
1911 +/*
1912 + * Return the index of the first span in cover whose beg is greater than val.
1913 + * If there is no such span, then cover->num is returned.
1914 + */
1915 +static size_t cover_find(cover, val)
1916 + cover_t *cover;
1917 + bound_t val;
1918 +{
1919 + size_t lo = 0, hi = cover->num;
1920 + while (lo < hi) {
1921 + size_t mid = (lo + hi) >> 1;
1922 + if (val < cover->span[mid].beg)
1923 + hi = mid;
1924 + else
1925 + lo = mid + 1;
1926 + }
1927 + return hi;
1928 +}
1929 +
1930 +/* Return true if val lies within any one of the spans in cover. */
1931 +static int cover_within(cover, val)
1932 + cover_t *cover;
1933 + bound_t val;
1934 +{
1935 + size_t pos = cover_find(cover, val);
1936 + return pos > 0 && val < cover->span[pos - 1].end;
1937 +}
1938 +
1939 +/*
1940 + * Add a new span to the list, but only if the new span does not overlap any
1941 + * spans already in the list. The new span covers the values beg..end-1. beg
1942 + * must be less than end.
1943 + *
1944 + * Keep the list sorted and merge adjacent spans. Grow the allocated space for
1945 + * the list as needed. On success, 0 is returned. If the new span overlaps any
1946 + * existing spans, then 1 is returned and the new span is not added to the
1947 + * list. If the new span is invalid because beg is greater than or equal to
1948 + * end, then -1 is returned. If the list needs to be grown but the memory
1949 + * allocation fails, then -2 is returned.
1950 + */
1951 +static int cover_add(cover, beg, end)
1952 + cover_t *cover;
1953 + bound_t beg;
1954 + bound_t end;
1955 +{
1956 + size_t pos;
1957 + int prec, foll;
1958 +
1959 + if (beg >= end)
1960 + /* The new span is invalid. */
1961 + return -1;
1962 +
1963 + /* Find where the new span should go, and make sure that it does not
1964 + overlap with any existing spans. */
1965 + pos = cover_find(cover, beg);
1966 + if ((pos > 0 && beg < cover->span[pos - 1].end) ||
1967 + (pos < cover->num && end > cover->span[pos].beg))
1968 + return 1;
1969 +
1970 + /* Check for adjacencies. */
1971 + prec = pos > 0 && beg == cover->span[pos - 1].end;
1972 + foll = pos < cover->num && end == cover->span[pos].beg;
1973 + if (prec && foll) {
1974 + /* The new span connects the preceding and following spans. Merge the
1975 + following span into the preceding span, and delete the following
1976 + span. */
1977 + cover->span[pos - 1].end = cover->span[pos].end;
1978 + cover->num--;
1979 + memmove(cover->span + pos, cover->span + pos + 1,
1980 + (cover->num - pos) * sizeof(span_t));
1981 + }
1982 + else if (prec)
1983 + /* The new span is adjacent only to the preceding span. Extend the end
1984 + of the preceding span. */
1985 + cover->span[pos - 1].end = end;
1986 + else if (foll)
1987 + /* The new span is adjacent only to the following span. Extend the
1988 + beginning of the following span. */
1989 + cover->span[pos].beg = beg;
1990 + else {
1991 + /* The new span has gaps between both the preceding and the following
1992 + spans. Assure that there is room and insert the span. */
1993 + if (cover->num == cover->max) {
1994 + size_t max = cover->max == 0 ? 16 : cover->max << 1;
1995 + span_t *span = realloc(cover->span, max * sizeof(span_t));
1996 + if (span == NULL)
1997 + return -2;
1998 + cover->span = span;
1999 + cover->max = max;
2000 + }
2001 + memmove(cover->span + pos + 1, cover->span + pos,
2002 + (cover->num - pos) * sizeof(span_t));
2003 + cover->num++;
2004 + cover->span[pos].beg = beg;
2005 + cover->span[pos].end = end;
2006 + }
2007 + return 0;
2008 +}
2009
2010
2011
2012 @@ -374,6 +493,29 @@ int extract_or_test_files(__G) /* return PK-type error code */
2013 }
2014 #endif /* !SFX || SFX_EXDIR */
2015
2016 + /* One more: initialize cover structure for bomb detection. Start with a
2017 + span that covers the central directory though the end of the file. */
2018 + if (G.cover == NULL) {
2019 + G.cover = malloc(sizeof(cover_t));
2020 + if (G.cover == NULL) {
2021 + Info(slide, 0x401, ((char *)slide,
2022 + LoadFarString(NotEnoughMemCover)));
2023 + return PK_MEM;
2024 + }
2025 + ((cover_t *)G.cover)->span = NULL;
2026 + ((cover_t *)G.cover)->max = 0;
2027 + }
2028 + ((cover_t *)G.cover)->num = 0;
2029 + if ((G.extra_bytes != 0 &&
2030 + cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
2031 + cover_add((cover_t *)G.cover,
2032 + G.extra_bytes + G.ecrec.offset_start_central_directory,
2033 + G.ziplen) != 0) {
2034 + Info(slide, 0x401, ((char *)slide,
2035 + LoadFarString(NotEnoughMemCover)));
2036 + return PK_MEM;
2037 + }
2038 +
2039 /*---------------------------------------------------------------------------
2040 The basic idea of this function is as follows. Since the central di-
2041 rectory lies at the end of the zipfile and the member files lie at the
2042 @@ -591,7 +733,8 @@ int extract_or_test_files(__G) /* return PK-type error code */
2043 if (error > error_in_archive)
2044 error_in_archive = error;
2045 /* ...and keep going (unless disk full or user break) */
2046 - if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
2047 + if (G.disk_full > 1 || error_in_archive == IZ_CTRLC ||
2048 + error == PK_BOMB) {
2049 /* clear reached_end to signal premature stop ... */
2050 reached_end = FALSE;
2051 /* ... and cancel scanning the central directory */
2052 @@ -1060,6 +1203,11 @@ static int extract_or_test_entrylist(__G__ numchunk,
2053
2054 /* seek_zipf(__G__ pInfo->offset); */
2055 request = G.pInfo->offset + G.extra_bytes;
2056 + if (cover_within((cover_t *)G.cover, request)) {
2057 + Info(slide, 0x401, ((char *)slide,
2058 + LoadFarString(OverlappedComponents)));
2059 + return PK_BOMB;
2060 + }
2061 inbuf_offset = request % INBUFSIZ;
2062 bufstart = request - inbuf_offset;
2063
2064 @@ -1591,6 +1739,18 @@ static int extract_or_test_entrylist(__G__ numchunk,
2065 return IZ_CTRLC; /* cancel operation by user request */
2066 }
2067 #endif
2068 + error = cover_add((cover_t *)G.cover, request,
2069 + G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
2070 + if (error < 0) {
2071 + Info(slide, 0x401, ((char *)slide,
2072 + LoadFarString(NotEnoughMemCover)));
2073 + return PK_MEM;
2074 + }
2075 + if (error != 0) {
2076 + Info(slide, 0x401, ((char *)slide,
2077 + LoadFarString(OverlappedComponents)));
2078 + return PK_BOMB;
2079 + }
2080 #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
2081 UserStop();
2082 #endif
2083 @@ -1992,6 +2152,34 @@ static int extract_or_test_member(__G) /* return PK-type error code */
2084 }
2085
2086 undefer_input(__G);
2087 +
2088 + if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
2089 + /* skip over data descriptor (harder than it sounds, due to signature
2090 + * ambiguity)
2091 + */
2092 +# define SIG 0x08074b50
2093 +# define LOW 0xffffffff
2094 + uch buf[12];
2095 + unsigned shy = 12 - readbuf((char *)buf, 12);
2096 + ulg crc = shy ? 0 : makelong(buf);
2097 + ulg clen = shy ? 0 : makelong(buf + 4);
2098 + ulg ulen = shy ? 0 : makelong(buf + 8); /* or high clen if ZIP64 */
2099 + if (crc == SIG && /* if not SIG, no signature */
2100 + (G.lrec.crc32 != SIG || /* if not SIG, have signature */
2101 + (clen == SIG && /* if not SIG, no signature */
2102 + ((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
2103 + (ulen == SIG && /* if not SIG, no signature */
2104 + (G.zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
2105 + /* if not SIG, have signature */
2106 + )))))
2107 + /* skip four more bytes to account for signature */
2108 + shy += 4 - readbuf((char *)buf, 4);
2109 + if (G.zip64)
2110 + shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
2111 + if (shy)
2112 + error = PK_ERR;
2113 + }
2114 +
2115 return error;
2116
2117 } /* end function extract_or_test_member() */
2118 diff --git a/globals.c b/globals.c
2119 index fa8cca5..1e0f608 100644
2120 --- a/globals.c
2121 +++ b/globals.c
2122 @@ -181,6 +181,7 @@ Uz_Globs *globalsCtor()
2123 # if (!defined(NO_TIMESTAMPS))
2124 uO.D_flag=1; /* default to '-D', no restoration of dir timestamps */
2125 # endif
2126 + G.cover = NULL; /* not allocated yet */
2127 #endif
2128
2129 uO.lflag=(-1);
2130 diff --git a/globals.h b/globals.h
2131 index 11b7215..2bdcdeb 100644
2132 --- a/globals.h
2133 +++ b/globals.h
2134 @@ -260,12 +260,15 @@ typedef struct Globals {
2135 ecdir_rec ecrec; /* used in unzip.c, extract.c */
2136 z_stat statbuf; /* used by main, mapname, check_for_newer */
2137
2138 + int zip64; /* true if Zip64 info in extra field */
2139 +
2140 int mem_mode;
2141 uch *outbufptr; /* extract.c static */
2142 ulg outsize; /* extract.c static */
2143 int reported_backslash; /* extract.c static */
2144 int disk_full;
2145 int newfile;
2146 + void **cover; /* used in extract.c for bomb detection */
2147
2148 int didCRlast; /* fileio static */
2149 ulg numlines; /* fileio static: number of lines printed */
2150 diff --git a/process.c b/process.c
2151 index 1e9a1e1..d2e4dc3 100644
2152 --- a/process.c
2153 +++ b/process.c
2154 @@ -637,6 +637,13 @@ void free_G_buffers(__G) /* releases all memory allocated in global vars */
2155 }
2156 #endif
2157
2158 + /* Free the cover span list and the cover structure. */
2159 + if (G.cover != NULL) {
2160 + free(*(G.cover));
2161 + free(G.cover);
2162 + G.cover = NULL;
2163 + }
2164 +
2165 } /* end function free_G_buffers() */
2166
2167
2168 @@ -1890,6 +1897,8 @@ int getZip64Data(__G__ ef_buf, ef_len)
2169 #define Z64FLGS 0xffff
2170 #define Z64FLGL 0xffffffff
2171
2172 + G.zip64 = FALSE;
2173 +
2174 if (ef_len == 0 || ef_buf == NULL)
2175 return PK_COOL;
2176
2177 @@ -1927,6 +1936,8 @@ int getZip64Data(__G__ ef_buf, ef_len)
2178 #if 0
2179 break; /* Expect only one EF_PKSZ64 block. */
2180 #endif /* 0 */
2181 +
2182 + G.zip64 = TRUE;
2183 }
2184
2185 /* Skip this extra field block. */
2186 diff --git a/unzip.h b/unzip.h
2187 index 5b2a326..ed24a5b 100644
2188 --- a/unzip.h
2189 +++ b/unzip.h
2190 @@ -645,6 +645,7 @@ typedef struct _Uzp_cdir_Rec {
2191 #define PK_NOZIP 9 /* zipfile not found */
2192 #define PK_PARAM 10 /* bad or illegal parameters specified */
2193 #define PK_FIND 11 /* no files found */
2194 +#define PK_BOMB 12 /* likely zip bomb */
2195 #define PK_DISK 50 /* disk full */
2196 #define PK_EOF 51 /* unexpected EOF */
2197
2198 From 6d351831be705cc26d897db44f878a978f4138fc Mon Sep 17 00:00:00 2001
2199 From: Mark Adler <madler@alumni.caltech.edu>
2200 Date: Thu, 25 Jul 2019 20:43:17 -0700
2201 Subject: [PATCH] Do not raise a zip bomb alert for a misplaced central
2202 directory.
2203
2204 There is a zip-like file in the Firefox distribution, omni.ja,
2205 which is a zip container with the central directory placed at the
2206 start of the file instead of after the local entries as required
2207 by the zip standard. This commit marks the actual location of the
2208 central directory, as well as the end of central directory records,
2209 as disallowed locations. This now permits such containers to not
2210 raise a zip bomb alert, where in fact there are no overlaps.
2211 ---
2212 extract.c | 25 +++++++++++++++++++------
2213 process.c | 6 ++++++
2214 unzpriv.h | 10 ++++++++++
2215 3 files changed, 35 insertions(+), 6 deletions(-)
2216
2217 diff --git a/extract.c b/extract.c
2218 index 0973a33..1b73cb0 100644
2219 --- a/extract.c
2220 +++ b/extract.c
2221 @@ -493,8 +493,11 @@ int extract_or_test_files(__G) /* return PK-type error code */
2222 }
2223 #endif /* !SFX || SFX_EXDIR */
2224
2225 - /* One more: initialize cover structure for bomb detection. Start with a
2226 - span that covers the central directory though the end of the file. */
2227 + /* One more: initialize cover structure for bomb detection. Start with
2228 + spans that cover any extra bytes at the start, the central directory,
2229 + the end of central directory record (including the Zip64 end of central
2230 + directory locator, if present), and the Zip64 end of central directory
2231 + record, if present. */
2232 if (G.cover == NULL) {
2233 G.cover = malloc(sizeof(cover_t));
2234 if (G.cover == NULL) {
2235 @@ -506,15 +509,25 @@ int extract_or_test_files(__G) /* return PK-type error code */
2236 ((cover_t *)G.cover)->max = 0;
2237 }
2238 ((cover_t *)G.cover)->num = 0;
2239 - if ((G.extra_bytes != 0 &&
2240 - cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
2241 - cover_add((cover_t *)G.cover,
2242 + if (cover_add((cover_t *)G.cover,
2243 G.extra_bytes + G.ecrec.offset_start_central_directory,
2244 - G.ziplen) != 0) {
2245 + G.extra_bytes + G.ecrec.offset_start_central_directory +
2246 + G.ecrec.size_central_directory) != 0) {
2247 Info(slide, 0x401, ((char *)slide,
2248 LoadFarString(NotEnoughMemCover)));
2249 return PK_MEM;
2250 }
2251 + if ((G.extra_bytes != 0 &&
2252 + cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
2253 + (G.ecrec.have_ecr64 &&
2254 + cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
2255 + G.ecrec.ec64_end) != 0) ||
2256 + cover_add((cover_t *)G.cover, G.ecrec.ec_start,
2257 + G.ecrec.ec_end) != 0) {
2258 + Info(slide, 0x401, ((char *)slide,
2259 + LoadFarString(OverlappedComponents)));
2260 + return PK_BOMB;
2261 + }
2262
2263 /*---------------------------------------------------------------------------
2264 The basic idea of this function is as follows. Since the central di-
2265 diff --git a/process.c b/process.c
2266 index d2e4dc3..d75d405 100644
2267 --- a/process.c
2268 +++ b/process.c
2269 @@ -1408,6 +1408,10 @@ static int find_ecrec64(__G__ searchlen) /* return PK-class error */
2270
2271 /* Now, we are (almost) sure that we have a Zip64 archive. */
2272 G.ecrec.have_ecr64 = 1;
2273 + G.ecrec.ec_start -= ECLOC64_SIZE+4;
2274 + G.ecrec.ec64_start = ecrec64_start_offset;
2275 + G.ecrec.ec64_end = ecrec64_start_offset +
2276 + 12 + makeint64(&byterec[ECREC64_LENGTH]);
2277
2278 /* Update the "end-of-central-dir offset" for later checks. */
2279 G.real_ecrec_offset = ecrec64_start_offset;
2280 @@ -1542,6 +1546,8 @@ static int find_ecrec(__G__ searchlen) /* return PK-class error */
2281 makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
2282 G.ecrec.zipfile_comment_length =
2283 makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
2284 + G.ecrec.ec_start = G.real_ecrec_offset;
2285 + G.ecrec.ec_end = G.ecrec.ec_start + 22 + G.ecrec.zipfile_comment_length;
2286
2287 /* Now, we have to read the archive comment, BEFORE the file pointer
2288 is moved away backwards to seek for a Zip64 ECLOC64 structure.
2289 diff --git a/unzpriv.h b/unzpriv.h
2290 index dc9eff5..297b3c7 100644
2291 --- a/unzpriv.h
2292 +++ b/unzpriv.h
2293 @@ -2185,6 +2185,16 @@ typedef struct VMStimbuf {
2294 int have_ecr64; /* valid Zip64 ecdir-record exists */
2295 int is_zip64_archive; /* Zip64 ecdir-record is mandatory */
2296 ush zipfile_comment_length;
2297 + zusz_t ec_start, ec_end; /* offsets of start and end of the
2298 + end of central directory record,
2299 + including if present the Zip64
2300 + end of central directory locator,
2301 + which immediately precedes the
2302 + end of central directory record */
2303 + zusz_t ec64_start, ec64_end; /* if have_ecr64 is true, then these
2304 + are the offsets of the start and
2305 + end of the Zip64 end of central
2306 + directory record */
2307 } ecdir_rec;
2308
2309
2310 From 6fe72291a5563cdbcd2bdd87e36528537b7cdcfb Mon Sep 17 00:00:00 2001
2311 From: Jakub Martisko <jamartis@redhat.com>
2312 Date: Mon, 18 Nov 2019 14:17:46 +0100
2313 Subject: [PATCH] update the man page
2314
2315 ---
2316 man/unzip.1 | 2 ++
2317 1 file changed, 2 insertions(+)
2318
2319 diff --git a/man/unzip.1 b/man/unzip.1
2320 index 21816d1..4d66073 100644
2321 --- a/man/unzip.1
2322 +++ b/man/unzip.1
2323 @@ -850,6 +850,8 @@ the specified zipfiles were not found.
2324 invalid options were specified on the command line.
2325 .IP 11
2326 no matching files were found.
2327 +.IP 12
2328 +invalid zip file with overlapped components (possible zip-bomb). The zip-bomb checks can be disabled by using the UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE environment variable.
2329 .IP 50
2330 the disk is (or was) full during extraction.
2331 .IP 51
2332 --
2333 2.23.0
2334
2335 From 5e2efcd633a4a1fb95a129a75508e7d769e767be Mon Sep 17 00:00:00 2001
2336 From: Mark Adler <madler@alumni.caltech.edu>
2337 Date: Sun, 9 Feb 2020 20:36:28 -0800
2338 Subject: [PATCH] Fix bug in UZbunzip2() that incorrectly updated G.incnt.
2339
2340 The update assumed a full buffer, which is not always full. This
2341 could result in a false overlapped element detection when a small
2342 bzip2-compressed file was unzipped. This commit remedies that.
2343 ---
2344 extract.c | 2 +-
2345 1 file changed, 1 insertion(+), 1 deletion(-)
2346
2347 diff --git a/extract.c b/extract.c
2348 index d9866f9..0cb7bfc 100644
2349 --- a/extract.c
2350 +++ b/extract.c
2351 @@ -3010,7 +3010,7 @@ __GDEF
2352 #endif
2353
2354 G.inptr = (uch *)bstrm.next_in;
2355 - G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */
2356 + G.incnt -= G.inptr - G.inbuf; /* reset for other routines */
2357
2358 uzbunzip_cleanup_exit:
2359 err = BZ2_bzDecompressEnd(&bstrm);
2360 From 5c572555cf5d80309a07c30cf7a54b2501493720 Mon Sep 17 00:00:00 2001
2361 From: Mark Adler <madler@alumni.caltech.edu>
2362 Date: Sun, 9 Feb 2020 21:39:09 -0800
2363 Subject: [PATCH] Fix bug in UZinflate() that incorrectly updated G.incnt.
2364
2365 The update assumed a full buffer, which is not always full. This
2366 could result in a false overlapped element detection when a small
2367 deflate-compressed file was unzipped using an old zlib. This
2368 commit remedies that.
2369 ---
2370 inflate.c | 2 +-
2371 1 file changed, 1 insertion(+), 1 deletion(-)
2372
2373 diff --git a/inflate.c b/inflate.c
2374 index 2f5a015..70e3cc0 100644
2375 --- a/inflate.c
2376 +++ b/inflate.c
2377 @@ -700,7 +700,7 @@ int UZinflate(__G__ is_defl64)
2378 G.dstrm.total_out));
2379
2380 G.inptr = (uch *)G.dstrm.next_in;
2381 - G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */
2382 + G.incnt -= G.inptr - G.inbuf; /* reset for other routines */
2383
2384 uzinflate_cleanup_exit:
2385 err = inflateReset(&G.dstrm);
2386 From 122050bac16fae82a460ff739fb1ca0f106e9d85 Mon Sep 17 00:00:00 2001
2387 From: Mark Adler <madler@alumni.caltech.edu>
2388 Date: Sat, 2 Jan 2021 13:09:34 -0800
2389 Subject: [PATCH] Determine Zip64 status entry-by-entry instead of for entire
2390 file.
2391
2392 Fixes a bug for zip files with mixed Zip64 and not Zip64 entries,
2393 which resulted in an incorrect data descriptor length. The bug is
2394 seen when a Zip64 entry precedes a non-Zip64 entry, in which case
2395 the data descriptor would have been assumed to be larger than it
2396 is, resulting in an incorrect bomb warning due to a perceived
2397 overlap with the next entry. This commit determines and saves the
2398 Zip64 status for each entry based on the central directory, and
2399 then computes the length of each data descriptor accordingly.
2400 ---
2401 extract.c | 5 +++--
2402 globals.h | 2 --
2403 process.c | 4 +---
2404 unzpriv.h | 1 +
2405 4 files changed, 5 insertions(+), 7 deletions(-)
2406
2407 diff --git a/extract.c b/extract.c
2408 index 504afd6..878817d 100644
2409 --- a/extract.c
2410 +++ b/extract.c
2411 @@ -658,6 +658,7 @@ int extract_or_test_files(__G) /* return PK-type error code */
2412 break;
2413 }
2414 }
2415 + G.pInfo->zip64 = FALSE;
2416 if ((error = do_string(__G__ G.crec.extra_field_length,
2417 EXTRA_FIELD)) != 0)
2418 {
2419 @@ -2187,12 +2188,12 @@ static int extract_or_test_member(__G) /* return PK-type error code */
2420 (clen == SIG && /* if not SIG, no signature */
2421 ((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
2422 (ulen == SIG && /* if not SIG, no signature */
2423 - (G.zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
2424 + (G.pInfo->zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
2425 /* if not SIG, have signature */
2426 )))))
2427 /* skip four more bytes to account for signature */
2428 shy += 4 - readbuf((char *)buf, 4);
2429 - if (G.zip64)
2430 + if (G.pInfo->zip64)
2431 shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
2432 if (shy)
2433 error = PK_ERR;
2434 diff --git a/globals.h b/globals.h
2435 index f9c6daf..a883c90 100644
2436 --- a/globals.h
2437 +++ b/globals.h
2438 @@ -261,8 +261,6 @@ typedef struct Globals {
2439 ecdir_rec ecrec; /* used in unzip.c, extract.c */
2440 z_stat statbuf; /* used by main, mapname, check_for_newer */
2441
2442 - int zip64; /* true if Zip64 info in extra field */
2443 -
2444 int mem_mode;
2445 uch *outbufptr; /* extract.c static */
2446 ulg outsize; /* extract.c static */
2447 diff --git a/process.c b/process.c
2448 index d75d405..d643c6f 100644
2449 --- a/process.c
2450 +++ b/process.c
2451 @@ -1903,8 +1903,6 @@ int getZip64Data(__G__ ef_buf, ef_len)
2452 #define Z64FLGS 0xffff
2453 #define Z64FLGL 0xffffffff
2454
2455 - G.zip64 = FALSE;
2456 -
2457 if (ef_len == 0 || ef_buf == NULL)
2458 return PK_COOL;
2459
2460 @@ -1943,7 +1941,7 @@ int getZip64Data(__G__ ef_buf, ef_len)
2461 break; /* Expect only one EF_PKSZ64 block. */
2462 #endif /* 0 */
2463
2464 - G.zip64 = TRUE;
2465 + G.pInfo->zip64 = TRUE;
2466 }
2467
2468 /* Skip this extra field block. */
2469 diff --git a/unzpriv.h b/unzpriv.h
2470 index 09f288e..75b3359 100644
2471 --- a/unzpriv.h
2472 +++ b/unzpriv.h
2473 @@ -2034,6 +2034,7 @@ typedef struct min_info {
2474 #ifdef UNICODE_SUPPORT
2475 unsigned GPFIsUTF8: 1; /* crec gen_purpose_flag UTF-8 bit 11 is set */
2476 #endif
2477 + unsigned zip64: 1; /* true if entry has Zip64 extra block */
2478 #ifndef SFX
2479 char Far *cfilname; /* central header version of filename */
2480 #endif
2481 From 5b44c818b96193b3e240f38f61985fa2bc780eb7 Mon Sep 17 00:00:00 2001
2482 From: Jakub Martisko <jamartis@redhat.com>
2483 Date: Tue, 30 Nov 2021 15:42:17 +0100
2484 Subject: [PATCH] Add an option to disable the zipbomb detection
2485
2486 This can be done by settting a newly introduced environment variable
2487 UNZIP_DISABLE_ZIPBOMB_DETECTION to {TRUE,True,true}. If the variable is unset, or
2488 set to any other value the zipbomb detection is left enabled.
2489
2490 Example:
2491 UNZIP_DISABLE_ZIPBOMB_DETECTION=True unzip ./zbsm.zip -d ./test
2492 ---
2493 extract.c | 85 ++++++++++++++++++++++++++++++-------------------------
2494 unzip.c | 15 ++++++++--
2495 unzip.h | 1 +
2496 3 files changed, 60 insertions(+), 41 deletions(-)
2497
2498 diff --git a/extract.c b/extract.c
2499 index 878817d..3e58071 100644
2500 --- a/extract.c
2501 +++ b/extract.c
2502 @@ -322,7 +322,8 @@ static ZCONST char Far BadExtraFieldCRC[] =
2503 static ZCONST char Far NotEnoughMemCover[] =
2504 "error: not enough memory for bomb detection\n";
2505 static ZCONST char Far OverlappedComponents[] =
2506 - "error: invalid zip file with overlapped components (possible zip bomb)\n";
2507 + "error: invalid zip file with overlapped components (possible zip bomb)\n \
2508 +To unzip the file anyway, rerun the command with UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE environmnent variable\n";
2509
2510
2511
2512 @@ -502,35 +503,37 @@ int extract_or_test_files(__G) /* return PK-type error code */
2513 the end of central directory record (including the Zip64 end of central
2514 directory locator, if present), and the Zip64 end of central directory
2515 record, if present. */
2516 - if (G.cover == NULL) {
2517 + if (uO.zipbomb == TRUE) {
2518 + if (G.cover == NULL) {
2519 G.cover = malloc(sizeof(cover_t));
2520 if (G.cover == NULL) {
2521 - Info(slide, 0x401, ((char *)slide,
2522 - LoadFarString(NotEnoughMemCover)));
2523 - return PK_MEM;
2524 + Info(slide, 0x401, ((char *)slide,
2525 + LoadFarString(NotEnoughMemCover)));
2526 + return PK_MEM;
2527 }
2528 ((cover_t *)G.cover)->span = NULL;
2529 ((cover_t *)G.cover)->max = 0;
2530 - }
2531 - ((cover_t *)G.cover)->num = 0;
2532 - if (cover_add((cover_t *)G.cover,
2533 - G.extra_bytes + G.ecrec.offset_start_central_directory,
2534 - G.extra_bytes + G.ecrec.offset_start_central_directory +
2535 - G.ecrec.size_central_directory) != 0) {
2536 + }
2537 + ((cover_t *)G.cover)->num = 0;
2538 + if (cover_add((cover_t *)G.cover,
2539 + G.extra_bytes + G.ecrec.offset_start_central_directory,
2540 + G.extra_bytes + G.ecrec.offset_start_central_directory +
2541 + G.ecrec.size_central_directory) != 0) {
2542 Info(slide, 0x401, ((char *)slide,
2543 - LoadFarString(NotEnoughMemCover)));
2544 + LoadFarString(NotEnoughMemCover)));
2545 return PK_MEM;
2546 - }
2547 - if ((G.extra_bytes != 0 &&
2548 - cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
2549 - (G.ecrec.have_ecr64 &&
2550 - cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
2551 - G.ecrec.ec64_end) != 0) ||
2552 - cover_add((cover_t *)G.cover, G.ecrec.ec_start,
2553 - G.ecrec.ec_end) != 0) {
2554 + }
2555 + if ((G.extra_bytes != 0 &&
2556 + cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
2557 + (G.ecrec.have_ecr64 &&
2558 + cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
2559 + G.ecrec.ec64_end) != 0) ||
2560 + cover_add((cover_t *)G.cover, G.ecrec.ec_start,
2561 + G.ecrec.ec_end) != 0) {
2562 Info(slide, 0x401, ((char *)slide,
2563 - LoadFarString(OverlappedComponents)));
2564 + LoadFarString(OverlappedComponents)));
2565 return PK_BOMB;
2566 + }
2567 }
2568
2569 /*---------------------------------------------------------------------------
2570 @@ -1222,10 +1225,12 @@ static int extract_or_test_entrylist(__G__ numchunk,
2571
2572 /* seek_zipf(__G__ pInfo->offset); */
2573 request = G.pInfo->offset + G.extra_bytes;
2574 - if (cover_within((cover_t *)G.cover, request)) {
2575 + if (uO.zipbomb == TRUE) {
2576 + if (cover_within((cover_t *)G.cover, request)) {
2577 Info(slide, 0x401, ((char *)slide,
2578 - LoadFarString(OverlappedComponents)));
2579 + LoadFarString(OverlappedComponents)));
2580 return PK_BOMB;
2581 + }
2582 }
2583 inbuf_offset = request % INBUFSIZ;
2584 bufstart = request - inbuf_offset;
2585 @@ -1758,17 +1763,19 @@ reprompt:
2586 return IZ_CTRLC; /* cancel operation by user request */
2587 }
2588 #endif
2589 - error = cover_add((cover_t *)G.cover, request,
2590 - G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
2591 - if (error < 0) {
2592 + if (uO.zipbomb == TRUE) {
2593 + error = cover_add((cover_t *)G.cover, request,
2594 + G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
2595 + if (error < 0) {
2596 Info(slide, 0x401, ((char *)slide,
2597 - LoadFarString(NotEnoughMemCover)));
2598 + LoadFarString(NotEnoughMemCover)));
2599 return PK_MEM;
2600 - }
2601 - if (error != 0) {
2602 + }
2603 + if (error != 0) {
2604 Info(slide, 0x401, ((char *)slide,
2605 - LoadFarString(OverlappedComponents)));
2606 + LoadFarString(OverlappedComponents)));
2607 return PK_BOMB;
2608 + }
2609 }
2610 #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
2611 UserStop();
2612 @@ -2171,8 +2178,8 @@ static int extract_or_test_member(__G) /* return PK-type error code */
2613 }
2614
2615 undefer_input(__G);
2616 -
2617 - if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
2618 + if (uO.zipbomb == TRUE) {
2619 + if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
2620 /* skip over data descriptor (harder than it sounds, due to signature
2621 * ambiguity)
2622 */
2623 @@ -2189,16 +2196,16 @@ static int extract_or_test_member(__G) /* return PK-type error code */
2624 ((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
2625 (ulen == SIG && /* if not SIG, no signature */
2626 (G.pInfo->zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
2627 - /* if not SIG, have signature */
2628 + /* if not SIG, have signature */
2629 )))))
2630 - /* skip four more bytes to account for signature */
2631 - shy += 4 - readbuf((char *)buf, 4);
2632 + /* skip four more bytes to account for signature */
2633 + shy += 4 - readbuf((char *)buf, 4);
2634 if (G.pInfo->zip64)
2635 - shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
2636 + shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
2637 if (shy)
2638 - error = PK_ERR;
2639 + error = PK_ERR;
2640 + }
2641 }
2642 -
2643 return error;
2644
2645 } /* end function extract_or_test_member() */
2646 diff --git a/unzip.c b/unzip.c
2647 index 8dbfc95..abb3644 100644
2648 --- a/unzip.c
2649 +++ b/unzip.c
2650 @@ -1329,10 +1329,9 @@ int uz_opts(__G__ pargc, pargv)
2651 int *pargc;
2652 char ***pargv;
2653 {
2654 - char **argv, *s;
2655 + char **argv, *s, *zipbomb_envar;
2656 int argc, c, error=FALSE, negative=0, showhelp=0;
2657
2658 -
2659 argc = *pargc;
2660 argv = *pargv;
2661
2662 @@ -1923,6 +1922,18 @@ opts_done: /* yes, very ugly...but only used by UnZipSFX with -x xlist */
2663 else
2664 G.extract_flag = TRUE;
2665
2666 + /* Disable the zipbomb detection, this is the only option set only via the shell variables but it should at least not clash with something in the future. */
2667 + zipbomb_envar = getenv("UNZIP_DISABLE_ZIPBOMB_DETECTION");
2668 + uO.zipbomb = TRUE;
2669 + if (zipbomb_envar != NULL) {
2670 + /* strcasecmp might be a better approach here but it is POSIX-only */
2671 + if ((strcmp ("TRUE", zipbomb_envar) == 0)
2672 + || (strcmp ("True", zipbomb_envar) == 0)
2673 + || (strcmp ("true",zipbomb_envar) == 0)) {
2674 + uO.zipbomb = FALSE;
2675 + }
2676 + }
2677 +
2678 *pargc = argc;
2679 *pargv = argv;
2680 return PK_OK;
2681 diff --git a/unzip.h b/unzip.h
2682 index ed24a5b..e7665e8 100644
2683 --- a/unzip.h
2684 +++ b/unzip.h
2685 @@ -559,6 +559,7 @@ typedef struct _UzpOpts {
2686 #ifdef UNIX
2687 int cflxflag; /* -^: allow control chars in extracted filenames */
2688 #endif
2689 + int zipbomb;
2690 #endif /* !FUNZIP */
2691 } UzpOpts;
2692
2693 --
2694 2.33.0
2695
2696 diff --git a/process.c b/process.c
2697 index d2a846e..cba2463 100644
2698 --- a/process.c
2699 +++ b/process.c
2700 @@ -2064,10 +2064,14 @@ int getUnicodeData(__G__ ef_buf, ef_len)
2701 G.unipath_checksum = makelong(offset + ef_buf);
2702 offset += 4;
2703
2704 + if (!G.filename_full) {
2705 + /* Check if we have a unicode extra section but no filename set */
2706 + return PK_ERR;
2707 + }
2708 +
2709 /*
2710 * Compute 32-bit crc
2711 */
2712 -
2713 chksum = crc32(chksum, (uch *)(G.filename_full),
2714 strlen(G.filename_full));
|