Compare commits

...
Sign in to create a new pull request.

26 commits

Author SHA1 Message Date
Jakub Martisko
5787660118 Port several downstream patches from rhel
Fixes for:
- RHEL-86228, RHEL-45997
- Some coverity issues
- CVE-2022-0529 and CVE-2022-0530 (thanks Stewart Smith for head up
  about these)
2026-07-27 11:44:42 +02:00
Fedora Release Engineering
a005784789 Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild 2026-07-17 08:13:31 +00:00
Fedora Release Engineering
dcc10bc2ce Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild 2026-01-17 19:38:54 +00:00
Jakub Martisko
97c9106ddc Another zipbomb patch 2025-08-20 12:53:58 +02:00
Fedora Release Engineering
392770fc88 Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild 2025-07-25 19:49:30 +00:00
Fedora Release Engineering
d68244a849 Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild 2025-01-19 13:50:13 +00:00
Jakub Martisko
8ce8569f5a Zipinfo: remove the extra %c in the help message
The extra %c caused invalid memory reads and thus a bogus output in the
help message.
Also fix the white4space fomrmating of the help message.
Related: RHEL-59972
2024-11-25 12:26:34 +01:00
Fedora Release Engineering
5db7630b97 Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild 2024-07-20 08:19:55 +00:00
Software Management Team
e198018c31 Eliminate use of obsolete %patchN syntax (#2283636) 2024-05-30 12:46:49 +02:00
Fedora Release Engineering
f9390b6599 Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild 2024-01-27 07:10:46 +00:00
Fedora Release Engineering
e377b9ac37 Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2023-07-22 17:10:48 +00:00
Radka Brychtova
21b04a7b44 initialize testsuite from /tests/unzip 2023-06-27 14:38:24 +00:00
Lukáš Zaoral
5f6875e430
migrate to SPDX license format 2023-04-13 14:46:00 +02:00
Siddhesh Poyarekar
890a253840 Fix length passed to wcstombs call (#2164068)
Resolves: #2164068
2023-01-25 07:12:56 -05:00
Fedora Release Engineering
0c458c2af2 Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2023-01-21 05:52:34 +00:00
Florian Weimer
42377b8175 Build with -std=gnu89 (#1750694) 2022-11-09 16:13:58 +01:00
Fedora Release Engineering
0d538e6135 Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2022-07-23 11:27:13 +00:00
Fedora Release Engineering
7b04f88bbb - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2022-01-22 03:34:25 +00:00
Jakub Martisko
d68949f359 Mention the zipbomb switch in the manpage 2021-12-16 11:44:15 +01:00
Jakub Martisko
a6d716afe0 Add a way to opt-out of the zipbomb detection 2021-12-13 12:10:08 +01:00
Jakub Martisko
ffbfeff45d Update the url
Resolves: rhbz#1867163
2021-11-09 15:06:04 +01:00
Fedora Release Engineering
0a410e7780 - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2021-07-23 20:05:29 +00:00
Jakub Martisko
a2a4f62759 Sync various zipbomb patches with rhel
unzip-zipbomb-part4 has been renamed to part6, and new parts 4 and 5, have
been ported from rhel

Resolves: 1953565
2021-04-28 16:03:51 +02:00
Jakub Martisko
88b0b70927 Fix: false positive in the zipbomb detection
Related: 1920632
2021-03-25 14:59:22 +01:00
4099f2bfa9 Merge #4 Minor spec file cleanup 2021-03-04 13:02:31 +00:00
1ef2c27df2 Minor spec file cleanup 2020-12-22 02:26:30 +00:00
16 changed files with 912 additions and 44 deletions

1
.fmf/version Normal file
View file

@ -0,0 +1 @@
1

6
plans/all.fmf Normal file
View file

@ -0,0 +1,6 @@
summary: Basic smoke test
discover:
how: fmf
url: https://src.fedoraproject.org/tests/unzip.git
execute:
how: tmt

View file

@ -0,0 +1,170 @@
From: Steven M. Schweda <sms@antinode.info>
Subject: Fix for CVE-2022-0529 and CVE-2022-0530
Bug-Debian: https://bugs.debian.org/1010355
X-Debian-version: 6.0-27
--- a/fileio.c
+++ b/fileio.c
@@ -171,8 +171,10 @@
static ZCONST char Far FilenameTooLongTrunc[] =
"warning: filename too long--truncating.\n";
#ifdef UNICODE_SUPPORT
+ static ZCONST char Far UFilenameCorrupt[] =
+ "error: Unicode filename corrupt.\n";
static ZCONST char Far UFilenameTooLongTrunc[] =
- "warning: Converted unicode filename too long--truncating.\n";
+ "warning: Converted Unicode filename too long--truncating.\n";
#endif
static ZCONST char Far ExtraFieldTooLong[] =
"warning: extra field too long (%d). Ignoring...\n";
@@ -2361,16 +2363,30 @@
/* convert UTF-8 to local character set */
fn = utf8_to_local_string(G.unipath_filename,
G.unicode_escape_all);
- /* make sure filename is short enough */
- if (strlen(fn) >= FILNAMSIZ) {
- fn[FILNAMSIZ - 1] = '\0';
+
+ /* 2022-07-22 SMS, et al. CVE-2022-0530
+ * Detect conversion failure, emit message.
+ * Continue with unconverted name.
+ */
+ if (fn == NULL)
+ {
Info(slide, 0x401, ((char *)slide,
- LoadFarString(UFilenameTooLongTrunc)));
- error = PK_WARN;
+ LoadFarString(UFilenameCorrupt)));
+ error = PK_ERR;
+ }
+ else
+ {
+ /* make sure filename is short enough */
+ if (strlen(fn) >= FILNAMSIZ) {
+ fn[FILNAMSIZ - 1] = '\0';
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(UFilenameTooLongTrunc)));
+ error = PK_WARN;
+ }
+ /* replace filename with converted UTF-8 */
+ strcpy(G.filename, fn);
+ free(fn);
}
- /* replace filename with converted UTF-8 */
- strcpy(G.filename, fn);
- free(fn);
}
# endif /* UNICODE_WCHAR */
if (G.unipath_filename != G.filename_full)
--- a/process.c
+++ b/process.c
@@ -222,6 +222,8 @@
"\nwarning: Unicode Path version > 1\n";
static ZCONST char Far UnicodeMismatchError[] =
"\nwarning: Unicode Path checksum invalid\n";
+ static ZCONST char Far UFilenameTooLongTrunc[] =
+ "warning: filename too long (P1) -- truncating.\n";
#endif
@@ -1915,7 +1917,7 @@
Sets both local header and central header fields. Not terribly clever,
but it means that this procedure is only called in one place.
- 2014-12-05 SMS.
+ 2014-12-05 SMS. (oCERT.org report.) CVE-2014-8141.
Added checks to ensure that enough data are available before calling
makeint64() or makelong(). Replaced various sizeof() values with
simple ("4" or "8") constants. (The Zip64 structures do not depend
@@ -1947,7 +1949,7 @@
if (eb_id == EF_PKSZ64)
{
- int offset = EB_HEADSIZE;
+ unsigned offset = EB_HEADSIZE;
if ((G.crec.ucsize == Z64FLGL) || (G.lrec.ucsize == Z64FLGL))
{
@@ -2046,7 +2049,7 @@
}
if (eb_id == EF_UNIPATH) {
- int offset = EB_HEADSIZE;
+ unsigned offset = EB_HEADSIZE;
ush ULen = eb_len - 5;
ulg chksum = CRCVAL_INITIAL;
@@ -2504,16 +2507,17 @@
int state_dependent;
int wsize = 0;
int max_bytes = MB_CUR_MAX;
- char buf[9];
+ char buf[ MB_CUR_MAX+ 1]; /* ("+1" not really needed?) */
char *buffer = NULL;
char *local_string = NULL;
+ size_t buffer_size; /* CVE-2022-0529 */
for (wsize = 0; wide_string[wsize]; wsize++) ;
if (max_bytes < MAX_ESCAPE_BYTES)
max_bytes = MAX_ESCAPE_BYTES;
-
- if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
+ buffer_size = wsize * max_bytes + 1; /* Reused below. */
+ if ((buffer = (char *)malloc( buffer_size)) == NULL) {
return NULL;
}
@@ -2551,8 +2555,28 @@
} else {
/* no MB for this wide */
/* use escape for wide character */
- char *escape_string = wide_to_escape_string(wide_string[i]);
- strcat(buffer, escape_string);
+ size_t buffer_len;
+ size_t escape_string_len;
+ char *escape_string;
+ int err_msg = 0;
+
+ escape_string = wide_to_escape_string(wide_string[i]);
+ buffer_len = strlen( buffer);
+ escape_string_len = strlen( escape_string);
+
+ /* Append escape string, as space allows. */
+ /* 2022-07-18 SMS, et al. CVE-2022-0529 */
+ if (escape_string_len > buffer_size- buffer_len- 1)
+ {
+ escape_string_len = buffer_size- buffer_len- 1;
+ if (err_msg == 0)
+ {
+ err_msg = 1;
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString( UFilenameTooLongTrunc)));
+ }
+ }
+ strncat( buffer, escape_string, escape_string_len);
free(escape_string);
}
}
@@ -2604,9 +2628,18 @@
ZCONST char *utf8_string;
int escape_all;
{
- zwchar *wide = utf8_to_wide_string(utf8_string);
- char *loc = wide_to_local_string(wide, escape_all);
- free(wide);
+ zwchar *wide;
+ char *loc = NULL;
+
+ wide = utf8_to_wide_string( utf8_string);
+
+ /* 2022-07-25 SMS, et al. CVE-2022-0530 */
+ if (wide != NULL)
+ {
+ loc = wide_to_local_string( wide, escape_all);
+ free( wide);
+ }
+
return loc;
}

View file

@ -0,0 +1,19 @@
From: Roy Tam
Subject: Handle Microsoft ZIP64 files by ignoring invalid "Total number of disks" field
Origin: https://sourceforge.net/p/infozip/bugs/42/
Bug: https://sourceforge.net/p/infozip/bugs/42/
Bug-Debian: https://bugs.debian.org/1064000
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/unzip/+bug/2051952
X-Debian-version: 6.0-29
--- a/process.c
+++ b/process.c
@@ -1281,7 +1281,7 @@
fprintf(stdout,"\nnumber of disks (ECR) %u, (ECLOC64) %lu\n",
G.ecrec.number_this_disk, ecloc64_total_disks); fflush(stdout);
#endif
- if ((G.ecrec.number_this_disk != 0xFFFF) &&
+ if ((G.ecrec.number_this_disk != 0xFFFF) && ecloc64_total_disks &&
(G.ecrec.number_this_disk != ecloc64_total_disks - 1)) {
/* Note: For some unknown reason, the developers at PKWARE decided to
store the "zip64 total disks" value as a counter starting from 1,

View file

@ -174,11 +174,11 @@ Index: unzip-6.0/unzip.c
+#else /* UNIX */
+static ZCONST char Far ZipInfoUsageLine3[] = "miscellaneous options:\n\
+ -h print header line -t print totals for listed files or for all\n\
+ -z print zipfile comment %c-T%c print file times in sortable decimal format\
+\n %c-C%c be case-insensitive %s\
+ -z print zipfile comment -T print file times in sortable decimal format\
+\n -C be case-insensitive %s\
+ -x exclude filenames that follow from listing\n\
+ -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
+ -I CHARSET specify a character encoding for UNIX and other archives\n";
+ -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
+ -I CHARSET specify a character encoding for UNIX and other archives\n";
+#endif /* !UNIX */
#ifdef MORE
static ZCONST char Far ZipInfoUsageLine4[] =
@ -196,8 +196,8 @@ Index: unzip-6.0/unzip.c
+ -U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields\n\
+ -C match filenames case-insensitively -L make (some) names \
+lowercase\n %-42s -V retain VMS version numbers\n%s\
+ -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
+ -I CHARSET specify a character encoding for UNIX and other archives\n\n";
+ -O CHARSET specify a character encoding for DOS, Windows and OS/2 archives\n\
+ -I CHARSET specify a character encoding for UNIX and other archives\n\n";
#else /* !VMS */
static ZCONST char Far UnzipUsageLine4[] = "\
modifiers:\n\

View file

@ -0,0 +1,15 @@
From: "Steven M. Schweda" <sms@antinode.info>
Subject: Fix lame code in fileio.c
Bug-Debian: https://bugs.debian.org/929502
X-Debian-version: 6.0-23
--- a/fileio.c
+++ b/fileio.c
@@ -2477,6 +2477,7 @@
*/
return (((zusz_t)sig[7]) << 56)
+ (((zusz_t)sig[6]) << 48)
+ + (((zusz_t)sig[5]) << 40)
+ (((zusz_t)sig[4]) << 32)
+ (zusz_t)((((ulg)sig[3]) << 24)
+ (((ulg)sig[2]) << 16)

11
unzip-6.0-sast.patch Normal file
View file

@ -0,0 +1,11 @@
--- a/envargs.c 2005-03-04 03:23:38.000000000 +0100
+++ b/envargs.c 2024-11-26 13:17:22.289650230 +0100
@@ -118,7 +118,7 @@
/* remove escape characters */
while ((argstart = MBSCHR(argstart, '\\')) != (char *)NULL) {
- strcpy(argstart, argstart + 1);
+ memmove(argstart, argstart + 1, strlen(argstart + 1) + 1);
if (*argstart)
++argstart;
}

View file

@ -0,0 +1,11 @@
--- unzip60/extract.c 2023-01-25 07:05:58.742254870 -0500
+++ unzip60.new/extract.c 2023-01-25 07:04:48.073435349 -0500
@@ -2889,7 +2889,7 @@ char *fnfilter(raw, space, size) /* co
strcpy( (char *)space, raw);
return (char *)space;
}
- woslen = wcstombs( newraw, wostring, (woslen * MB_CUR_MAX) + 1);
+ woslen = wcstombs( newraw, wostring, woslen + 1);
if (size > 0) {
slim = space + size - 4;

15
unzip-gnu89-build.patch Normal file
View file

@ -0,0 +1,15 @@
unzip uses C89-only features, so it needs to be built in C89 mode.
diff --git a/unix/Makefile b/unix/Makefile
index ab32270cf4b9b2cf..5eabbe13095e1f58 100644
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -545,7 +545,7 @@ generic: flags # now try autoconfigure first
# make $(MAKEF) unzips CF="${CF} `cat flags`"
generic_gcc:
- $(MAKE) $(MAKEF) generic CC=gcc IZ_BZIP2="$(IZ_BZIP2)"
+ $(MAKE) $(MAKEF) generic CC="gcc -std=gnu89" IZ_BZIP2="$(IZ_BZIP2)"
# extensions to perform SVR4 package-creation after compilation
generic_pkg: generic svr4package

View file

@ -16,7 +16,7 @@ index 21816d1..4d66073 100644
.IP 11
no matching files were found.
+.IP 12
+invalid zip file with overlapped components (possible zip bomb).
+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.
.IP 50
the disk is (or was) full during extraction.
.IP 51

25
unzip-zipbomb-part4.patch Normal file
View file

@ -0,0 +1,25 @@
From 5e2efcd633a4a1fb95a129a75508e7d769e767be Mon Sep 17 00:00:00 2001
From: Mark Adler <madler@alumni.caltech.edu>
Date: Sun, 9 Feb 2020 20:36:28 -0800
Subject: [PATCH] Fix bug in UZbunzip2() that incorrectly updated G.incnt.
The update assumed a full buffer, which is not always full. This
could result in a false overlapped element detection when a small
bzip2-compressed file was unzipped. This commit remedies that.
---
extract.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extract.c b/extract.c
index d9866f9..0cb7bfc 100644
--- a/extract.c
+++ b/extract.c
@@ -3010,7 +3010,7 @@ __GDEF
#endif
G.inptr = (uch *)bstrm.next_in;
- G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */
+ G.incnt -= G.inptr - G.inbuf; /* reset for other routines */
uzbunzip_cleanup_exit:
err = BZ2_bzDecompressEnd(&bstrm);

26
unzip-zipbomb-part5.patch Normal file
View file

@ -0,0 +1,26 @@
From 5c572555cf5d80309a07c30cf7a54b2501493720 Mon Sep 17 00:00:00 2001
From: Mark Adler <madler@alumni.caltech.edu>
Date: Sun, 9 Feb 2020 21:39:09 -0800
Subject: [PATCH] Fix bug in UZinflate() that incorrectly updated G.incnt.
The update assumed a full buffer, which is not always full. This
could result in a false overlapped element detection when a small
deflate-compressed file was unzipped using an old zlib. This
commit remedies that.
---
inflate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/inflate.c b/inflate.c
index 2f5a015..70e3cc0 100644
--- a/inflate.c
+++ b/inflate.c
@@ -700,7 +700,7 @@ int UZinflate(__G__ is_defl64)
G.dstrm.total_out));
G.inptr = (uch *)G.dstrm.next_in;
- G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */
+ G.incnt -= G.inptr - G.inbuf; /* reset for other routines */
uzinflate_cleanup_exit:
err = inflateReset(&G.dstrm);

95
unzip-zipbomb-part6.patch Normal file
View file

@ -0,0 +1,95 @@
From 122050bac16fae82a460ff739fb1ca0f106e9d85 Mon Sep 17 00:00:00 2001
From: Mark Adler <madler@alumni.caltech.edu>
Date: Sat, 2 Jan 2021 13:09:34 -0800
Subject: [PATCH] Determine Zip64 status entry-by-entry instead of for entire
file.
Fixes a bug for zip files with mixed Zip64 and not Zip64 entries,
which resulted in an incorrect data descriptor length. The bug is
seen when a Zip64 entry precedes a non-Zip64 entry, in which case
the data descriptor would have been assumed to be larger than it
is, resulting in an incorrect bomb warning due to a perceived
overlap with the next entry. This commit determines and saves the
Zip64 status for each entry based on the central directory, and
then computes the length of each data descriptor accordingly.
---
extract.c | 5 +++--
globals.h | 2 --
process.c | 4 +---
unzpriv.h | 1 +
4 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/extract.c b/extract.c
index 504afd6..878817d 100644
--- a/extract.c
+++ b/extract.c
@@ -658,6 +658,7 @@ int extract_or_test_files(__G) /* return PK-type error code */
break;
}
}
+ G.pInfo->zip64 = FALSE;
if ((error = do_string(__G__ G.crec.extra_field_length,
EXTRA_FIELD)) != 0)
{
@@ -2187,12 +2188,12 @@ static int extract_or_test_member(__G) /* return PK-type error code */
(clen == SIG && /* if not SIG, no signature */
((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
(ulen == SIG && /* if not SIG, no signature */
- (G.zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
+ (G.pInfo->zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
/* if not SIG, have signature */
)))))
/* skip four more bytes to account for signature */
shy += 4 - readbuf((char *)buf, 4);
- if (G.zip64)
+ if (G.pInfo->zip64)
shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
if (shy)
error = PK_ERR;
diff --git a/globals.h b/globals.h
index f9c6daf..a883c90 100644
--- a/globals.h
+++ b/globals.h
@@ -261,8 +261,6 @@ typedef struct Globals {
ecdir_rec ecrec; /* used in unzip.c, extract.c */
z_stat statbuf; /* used by main, mapname, check_for_newer */
- int zip64; /* true if Zip64 info in extra field */
-
int mem_mode;
uch *outbufptr; /* extract.c static */
ulg outsize; /* extract.c static */
diff --git a/process.c b/process.c
index d75d405..d643c6f 100644
--- a/process.c
+++ b/process.c
@@ -1903,8 +1903,6 @@ int getZip64Data(__G__ ef_buf, ef_len)
#define Z64FLGS 0xffff
#define Z64FLGL 0xffffffff
- G.zip64 = FALSE;
-
if (ef_len == 0 || ef_buf == NULL)
return PK_COOL;
@@ -1943,7 +1941,7 @@ int getZip64Data(__G__ ef_buf, ef_len)
break; /* Expect only one EF_PKSZ64 block. */
#endif /* 0 */
- G.zip64 = TRUE;
+ G.pInfo->zip64 = TRUE;
}
/* Skip this extra field block. */
diff --git a/unzpriv.h b/unzpriv.h
index 09f288e..75b3359 100644
--- a/unzpriv.h
+++ b/unzpriv.h
@@ -2034,6 +2034,7 @@ typedef struct min_info {
#ifdef UNICODE_SUPPORT
unsigned GPFIsUTF8: 1; /* crec gen_purpose_flag UTF-8 bit 11 is set */
#endif
+ unsigned zip64: 1; /* true if entry has Zip64 extra block */
#ifndef SFX
char Far *cfilname; /* central header version of filename */
#endif

172
unzip-zipbomb-part7.patch Normal file
View file

@ -0,0 +1,172 @@
From af0d07f95809653b669d88aa0f424c6d5aa48ba0 Mon Sep 17 00:00:00 2001
From: Mark Adler <fork@madler.net>
Date: Sat, 2 Jul 2022 14:35:04 -0700
Subject: [PATCH] Be more liberal in the acceptance of data descriptors.
Previously the zip64 flag determined the size of the lengths in the
data descriptor. This is compliant with the zip format. However, a
bug in the Java zip library results in an incorrect setting of that
flag. This commit permits either 32-bit or 64-bit lengths, auto-
detecting which it is, which works around the Java bug.
---
extract.c | 146 +++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 123 insertions(+), 23 deletions(-)
diff --git a/extract.c b/extract.c
index 878817d..b1c74df 100644
--- a/extract.c
+++ b/extract.c
@@ -2173,30 +2173,130 @@ static int extract_or_test_member(__G) /* return PK-type error code */
undefer_input(__G);
if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
- /* skip over data descriptor (harder than it sounds, due to signature
- * ambiguity)
- */
-# define SIG 0x08074b50
-# define LOW 0xffffffff
- uch buf[12];
- unsigned shy = 12 - readbuf((char *)buf, 12);
- ulg crc = shy ? 0 : makelong(buf);
- ulg clen = shy ? 0 : makelong(buf + 4);
- ulg ulen = shy ? 0 : makelong(buf + 8); /* or high clen if ZIP64 */
- if (crc == SIG && /* if not SIG, no signature */
- (G.lrec.crc32 != SIG || /* if not SIG, have signature */
- (clen == SIG && /* if not SIG, no signature */
- ((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
- (ulen == SIG && /* if not SIG, no signature */
- (G.pInfo->zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
- /* if not SIG, have signature */
- )))))
- /* skip four more bytes to account for signature */
- shy += 4 - readbuf((char *)buf, 4);
- if (G.pInfo->zip64)
- shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
- if (shy)
+ // Skip over the data descriptor. We need to correctly position the
+ // read pointer after the data descriptor for the proper detection of
+ // overlapped zip file components.
+ //
+ // We need to resolve an ambiguity over four possible data descriptor
+ // formats. We check for all four, and pick the longest match. The data
+ // descriptor can have a signature or not, and it can use four or
+ // eight-byte lengths. The zip format requires resolving the ambiguity
+ // of a signature or not, but it uses the zip64 flag to determine
+ // whether the lengths are four or eight bytes. However there is a bug
+ // in the Java zip library that applies the wrong value of that flag.
+ // This works around that bug by always trying both length formats.
+ //
+ // So why the longest match? And does this resolve the ambiguity? No,
+ // it doesn't definitively resolve the ambiguity. However choosing the
+ // longest match at least resolves it for a normal zip file, where the
+ // bytes following the data descriptor must be another zip signature
+ // that is not a data descriptor signature. There are a few specific
+ // cases for which more than one of the formats will match the given
+ // CRC and lengths. The most plausible is between four and eight-byte
+ // lengths, either with or without a signature. That only occurs for an
+ // entry with an uncompressed size of zero. We consider the data
+ // descriptor to be a vector of four-byte values. Then the possible
+ // data descriptors are [(s) 0 c 0] and [(s) 0 c 0 0 0], where (s) is
+ // the optional signature, and c is the compressed length. c would be
+ // two for the Deflate compressed data format. These look the same, so
+ // if the file contains [(s) 0 c 0 0 0], then we cannot discriminate
+ // them. However if the data descriptor was intended to be [(s) 0 c 0],
+ // then it has been followed by eight zero bytes in the zip file for
+ // some reason. For a normal zip file this cannot be the case. The data
+ // descriptor would always be immediately followed by another zip file
+ // signature, which is four bytes that are not zeros. The other cases
+ // where more than one format matches are vanishingly unlikely, but the
+ // longest match strategy resolves those as well in a normal zip file.
+ // Those pairs are [s s s] vs. [s s s s], [s s s] vs. [s s s 0 s 0],
+ // and [s s s s s] vs. [s s s s s s]. For all, s is the signature for a
+ // data descriptor. For the first two we have an entry whose CRC,
+ // compressed length, and uncompressed length are all equal (!), and
+ // are all equal to the signature (!!). If this occurs, clearly someone
+ // is messing with us. However the strategy works nonetheless. We see
+ // that if the shorter descriptor, [s s s] were what was intended, then
+ // it has been followed by either four zero bytes or a data descriptor
+ // signature. Neither can occur for a normal zip file, where it must be
+ // followed by a signature that is not a data descriptor signature. So
+ // the longest match is the correct choice. The final case is outright
+ // insane, since the compressed and uncompressed lengths are the data
+ // descriptor signature repeated twice to make a 64-bit length, which
+ // is about 6e17. The largest drive available as I write this is 100TB,
+ // which is one six thousandth of that length. If I apply Moore's law
+ // to drive capacity, we might get to 6e17 about 25 years from now. If
+ // this code is still in use then (I've seen other code I've written in
+ // use for over 30 years), then we're still in luck. A data descriptor
+ // cannot be followed by a data descriptor signature in a normal zip
+ // file. The longest match strategy continues to work.
+ //
+ // So what is a not normal zip file, where these assumptions might fall
+ // apart? zip files have been used in a non-standard way as a poor
+ // substitute for a file system, with entries deleted and perhaps
+ // others replacing them partially, with fragmented zip files being the
+ // result. Then all bets are off as to what might or might not follow a
+ // data descriptor. Though if this sort of data descriptor ambiguity
+ // falls in one of those gaps, then there should be no adverse
+ // consequences for picking the unintended one.
+ int len = 0;
+# define SIG 0x08074b50 // optional data descriptor signature
+#ifdef LARGE_FILE_SUPPORT
+ uch buf[24];
+ int got = readbuf((char *)buf, sizeof(buf));
+ if (got >= 24 && makelong(buf) == SIG &&
+ makelong(buf + 4) == G.lrec.crc32 &&
+ makeint64(buf + 8) == G.lrec.csize &&
+ makeint64(buf + 16) == G.lrec.ucsize)
+ // Have a data descriptor with a signature and 64-bit lengths.
+ len = 24;
+ else if (got >= 20 && makelong(buf) == G.lrec.crc32 &&
+ makeint64(buf + 4) == G.lrec.csize &&
+ makeint64(buf + 12) == G.lrec.ucsize)
+ // Have a data descriptor with no signature and 64-bit lengths.
+ len = 20;
+ else if ((G.lrec.csize >> 32) == 0 && (G.lrec.ucsize >> 32) == 0)
+ // Both lengths are short enough to fit in 32 bits.
+#else
+ uch buf[16];
+ int got = readbuf((char *)buf, sizeof(buf));
+#endif
+ {
+ if (got >= 16 && makelong(buf) == SIG &&
+ makelong(buf + 4) == G.lrec.crc32 &&
+ makelong(buf + 8) == G.lrec.csize &&
+ makelong(buf + 12) == G.lrec.ucsize)
+ // Have a data descriptor with a signature and 32-bit lengths.
+ len = 16;
+ else if (got >= 12 && makelong(buf) == G.lrec.crc32 &&
+ makelong(buf + 4) == G.lrec.csize &&
+ makelong(buf + 8) == G.lrec.ucsize)
+ // Have a data descriptor with no signature and 32-bit lengths.
+ len = 12;
+ }
+ if (len == 0)
+ // There is no data descriptor that matches the entry CRC and
+ // length values.
error = PK_ERR;
+
+ // Back up got-len bytes, to position the read pointer after the data
+ // descriptor. Or to where the data descriptor was supposed to be, in
+ // the event none was found.
+ int back = got - len;
+ if (G.incnt + back > INBUFSIZ) {
+ // Need to load the preceding buffer. We've been here before.
+ G.cur_zipfile_bufstart -= INBUFSIZ;
+#ifdef USE_STRM_INPUT
+ zfseeko(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET);
+#else /* !USE_STRM_INPUT */
+ zlseek(G.zipfd, G.cur_zipfile_bufstart, SEEK_SET);
+#endif /* ?USE_STRM_INPUT */
+ read(G.zipfd, (char *)G.inbuf, INBUFSIZ);
+ G.incnt -= INBUFSIZ - back;
+ G.inptr += INBUFSIZ - back;
+ }
+ else {
+ // Back up within current buffer.
+ G.incnt += back;
+ G.inptr -= back;
+ }
}
return error;

202
unzip-zipbomb-switch.patch Normal file
View file

@ -0,0 +1,202 @@
From 5b44c818b96193b3e240f38f61985fa2bc780eb7 Mon Sep 17 00:00:00 2001
From: Jakub Martisko <jamartis@redhat.com>
Date: Tue, 30 Nov 2021 15:42:17 +0100
Subject: [PATCH] Add an option to disable the zipbomb detection
This can be done by settting a newly introduced environment variable
UNZIP_DISABLE_ZIPBOMB_DETECTION to {TRUE,True,true}. If the variable is unset, or
set to any other value the zipbomb detection is left enabled.
Example:
UNZIP_DISABLE_ZIPBOMB_DETECTION=True unzip ./zbsm.zip -d ./test
---
extract.c | 85 ++++++++++++++++++++++++++++++-------------------------
unzip.c | 15 ++++++++--
unzip.h | 1 +
3 files changed, 60 insertions(+), 41 deletions(-)
diff --git a/extract.c b/extract.c
index 878817d..3e58071 100644
--- a/extract.c
+++ b/extract.c
@@ -322,7 +322,8 @@ static ZCONST char Far BadExtraFieldCRC[] =
static ZCONST char Far NotEnoughMemCover[] =
"error: not enough memory for bomb detection\n";
static ZCONST char Far OverlappedComponents[] =
- "error: invalid zip file with overlapped components (possible zip bomb)\n";
+ "error: invalid zip file with overlapped components (possible zip bomb)\n \
+To unzip the file anyway, rerun the command with UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE environmnent variable\n";
@@ -502,35 +503,37 @@ int extract_or_test_files(__G) /* return PK-type error code */
the end of central directory record (including the Zip64 end of central
directory locator, if present), and the Zip64 end of central directory
record, if present. */
- if (G.cover == NULL) {
+ if (uO.zipbomb == TRUE) {
+ if (G.cover == NULL) {
G.cover = malloc(sizeof(cover_t));
if (G.cover == NULL) {
- Info(slide, 0x401, ((char *)slide,
- LoadFarString(NotEnoughMemCover)));
- return PK_MEM;
+ Info(slide, 0x401, ((char *)slide,
+ LoadFarString(NotEnoughMemCover)));
+ return PK_MEM;
}
((cover_t *)G.cover)->span = NULL;
((cover_t *)G.cover)->max = 0;
- }
- ((cover_t *)G.cover)->num = 0;
- if (cover_add((cover_t *)G.cover,
- G.extra_bytes + G.ecrec.offset_start_central_directory,
- G.extra_bytes + G.ecrec.offset_start_central_directory +
- G.ecrec.size_central_directory) != 0) {
+ }
+ ((cover_t *)G.cover)->num = 0;
+ if (cover_add((cover_t *)G.cover,
+ G.extra_bytes + G.ecrec.offset_start_central_directory,
+ G.extra_bytes + G.ecrec.offset_start_central_directory +
+ G.ecrec.size_central_directory) != 0) {
Info(slide, 0x401, ((char *)slide,
- LoadFarString(NotEnoughMemCover)));
+ LoadFarString(NotEnoughMemCover)));
return PK_MEM;
- }
- if ((G.extra_bytes != 0 &&
- cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
- (G.ecrec.have_ecr64 &&
- cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
- G.ecrec.ec64_end) != 0) ||
- cover_add((cover_t *)G.cover, G.ecrec.ec_start,
- G.ecrec.ec_end) != 0) {
+ }
+ if ((G.extra_bytes != 0 &&
+ cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
+ (G.ecrec.have_ecr64 &&
+ cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
+ G.ecrec.ec64_end) != 0) ||
+ cover_add((cover_t *)G.cover, G.ecrec.ec_start,
+ G.ecrec.ec_end) != 0) {
Info(slide, 0x401, ((char *)slide,
- LoadFarString(OverlappedComponents)));
+ LoadFarString(OverlappedComponents)));
return PK_BOMB;
+ }
}
/*---------------------------------------------------------------------------
@@ -1222,10 +1225,12 @@ static int extract_or_test_entrylist(__G__ numchunk,
/* seek_zipf(__G__ pInfo->offset); */
request = G.pInfo->offset + G.extra_bytes;
- if (cover_within((cover_t *)G.cover, request)) {
+ if (uO.zipbomb == TRUE) {
+ if (cover_within((cover_t *)G.cover, request)) {
Info(slide, 0x401, ((char *)slide,
- LoadFarString(OverlappedComponents)));
+ LoadFarString(OverlappedComponents)));
return PK_BOMB;
+ }
}
inbuf_offset = request % INBUFSIZ;
bufstart = request - inbuf_offset;
@@ -1758,17 +1763,19 @@ reprompt:
return IZ_CTRLC; /* cancel operation by user request */
}
#endif
- error = cover_add((cover_t *)G.cover, request,
- G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
- if (error < 0) {
+ if (uO.zipbomb == TRUE) {
+ error = cover_add((cover_t *)G.cover, request,
+ G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
+ if (error < 0) {
Info(slide, 0x401, ((char *)slide,
- LoadFarString(NotEnoughMemCover)));
+ LoadFarString(NotEnoughMemCover)));
return PK_MEM;
- }
- if (error != 0) {
+ }
+ if (error != 0) {
Info(slide, 0x401, ((char *)slide,
- LoadFarString(OverlappedComponents)));
+ LoadFarString(OverlappedComponents)));
return PK_BOMB;
+ }
}
#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
UserStop();
@@ -2171,8 +2178,8 @@ static int extract_or_test_member(__G) /* return PK-type error code */
}
undefer_input(__G);
-
- if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
+ if (uO.zipbomb == TRUE) {
+ if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
// Skip over the data descriptor. We need to correctly position the
// read pointer after the data descriptor for the proper detection of
// overlapped zip file components.
@@ -2189,8 +2196,8 @@ static int extract_or_test_member(__G) /* return PK-type error code */
G.incnt += back;
G.inptr -= back;
}
+ }
}
-
return error;
} /* end function extract_or_test_member() */
diff --git a/unzip.c b/unzip.c
index 8dbfc95..abb3644 100644
--- a/unzip.c
+++ b/unzip.c
@@ -1329,10 +1329,9 @@ int uz_opts(__G__ pargc, pargv)
int *pargc;
char ***pargv;
{
- char **argv, *s;
+ char **argv, *s, *zipbomb_envar;
int argc, c, error=FALSE, negative=0, showhelp=0;
-
argc = *pargc;
argv = *pargv;
@@ -1923,6 +1922,18 @@ opts_done: /* yes, very ugly...but only used by UnZipSFX with -x xlist */
else
G.extract_flag = TRUE;
+ /* 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. */
+ zipbomb_envar = getenv("UNZIP_DISABLE_ZIPBOMB_DETECTION");
+ uO.zipbomb = TRUE;
+ if (zipbomb_envar != NULL) {
+ /* strcasecmp might be a better approach here but it is POSIX-only */
+ if ((strcmp ("TRUE", zipbomb_envar) == 0)
+ || (strcmp ("True", zipbomb_envar) == 0)
+ || (strcmp ("true",zipbomb_envar) == 0)) {
+ uO.zipbomb = FALSE;
+ }
+ }
+
*pargc = argc;
*pargv = argv;
return PK_OK;
diff --git a/unzip.h b/unzip.h
index ed24a5b..e7665e8 100644
--- a/unzip.h
+++ b/unzip.h
@@ -559,6 +559,7 @@ typedef struct _UzpOpts {
#ifdef UNIX
int cflxflag; /* -^: allow control chars in extracted filenames */
#endif
+ int zipbomb;
#endif /* !FUNZIP */
} UzpOpts;
--
2.33.0

View file

@ -1,4 +1,3 @@
# Settings for EL <= 7
%if 0%{?rhel} && 0%{?rhel} <= 7
%{!?__global_ldflags: %global __global_ldflags -Wl,-z,relro}
@ -7,8 +6,8 @@
Summary: A utility for unpacking zip files
Name: unzip
Version: 6.0
Release: 50%{?dist}
License: BSD
Release: 71%{?dist}
License: Info-ZIP
Source: http://downloads.sourceforge.net/infozip/unzip60.tar.gz
# Not sent to upstream.
@ -68,8 +67,24 @@ Patch26: unzip-zipbomb-part1.patch
Patch27: unzip-zipbomb-part2.patch
Patch28: unzip-zipbomb-part3.patch
Patch29: unzip-zipbomb-manpage.patch
Patch30: unzip-zipbomb-part4.patch
Patch31: unzip-zipbomb-part5.patch
Patch32: unzip-zipbomb-part6.patch
Patch33: unzip-zipbomb-part7.patch
Patch34: unzip-zipbomb-switch.patch
URL: http://www.info-zip.org/UnZip.html
Patch35: unzip-gnu89-build.patch
Patch36: unzip-6.0-wcstombs-fortify.patch
Patch37: unzip-6.0-fix-warning-messages-on-big-files.patch
Patch38: unzip-6.0-sast.patch
Patch39: unzip-6.0-RHEL-86228.patch
#From Debian
Patch40: unzip-6.0-CVE-2022-0529-and-0530.patch
URL: http://infozip.sourceforge.net
BuildRequires: make
BuildRequires: bzip2-devel, gcc
@ -86,47 +101,57 @@ a zip archive.
%prep
%setup -q -n unzip60
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
%patch24 -p1
%patch25 -p1
%patch -P1 -p1
%patch -P2 -p1
%patch -P3 -p1
%patch -P4 -p1
%patch -P5 -p1
%patch -P6 -p1
%patch -P7 -p1
%patch -P8 -p1
%patch -P9 -p1
%patch -P10 -p1
%patch -P11 -p1
%patch -P12 -p1
%patch -P13 -p1
%patch -P14 -p1
%patch -P15 -p1
%patch -P16 -p1
%patch -P17 -p1
%patch -P18 -p1
%patch -P19 -p1
%patch -P20 -p1
%patch -P21 -p1
%patch -P22 -p1
%patch -P23 -p1
%patch -P24 -p1
%patch -P25 -p1
%patch26 -p1
%patch27 -p1
%patch28 -p1
%patch29 -p1
%patch -P26 -p1
%patch -P27 -p1
%patch -P28 -p1
%patch -P29 -p1
%patch -P30 -p1
%patch -P31 -p1
%patch -P32 -p1
%patch -P33 -p1
%patch -P34 -p1
%patch -P35 -p1
%patch -P36 -p1
%patch -P37 -p1
%patch -P38 -p1
%patch -P39 -p1
%patch -P40 -p1
%build
# IZ_HAVE_UXUIDGID is needed for right functionality of unzip -X
# NOMEMCPY solve problem with memory overlapping - decomression is slowly,
# NOMEMCPY solve problem with memory overlapping - decompression is slowly,
# but successfull.
%make_build -f unix/Makefile CF_NOOPT="-I. -DUNIX $RPM_OPT_FLAGS -DNOMEMCPY -DIZ_HAVE_UXUIDGID -DNO_LCHMOD" \
LFLAGS2="%{?__global_ldflags}" generic_gcc
%install
rm -rf $RPM_BUILD_ROOT
make -f unix/Makefile prefix=$RPM_BUILD_ROOT%{_prefix} MANDIR=$RPM_BUILD_ROOT/%{_mandir}/man1 INSTALL="cp -p" install
make -f unix/Makefile prefix=$RPM_BUILD_ROOT%{_prefix} MANDIR=$RPM_BUILD_ROOT%{_mandir}/man1 INSTALL="cp -p" install
%files
%license LICENSE COPYING.OLD
@ -135,6 +160,81 @@ make -f unix/Makefile prefix=$RPM_BUILD_ROOT%{_prefix} MANDIR=$RPM_BUILD_ROOT/%{
%{_mandir}/*/*
%changelog
* Wed Jul 22 2026 Jakub Martisko <jamartis@redhat.com> - 6.0-71
- Port some RHEL downstream patches to fedora
- Fixes for RHEL-86228, RHEL-45997 + some issues found by coverity and other scans
- Fixes for CVE-2022-0529 and 2022-0530 (Thanks Stewart Smith for the Heads up about these)
* Fri Jul 17 2026 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-70
- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
* Sat Jan 17 2026 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-69
- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild
* Wed Aug 20 2025 Jakub Martisko <jamartis@redhat.com> - 6.0-68
- Another zipmbomb patch
Resolves: rhbz#2360938
* Fri Jul 25 2025 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-67
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
* Sun Jan 19 2025 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-66
- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild
* Mon Nov 25 2024 Jakub Martisko <jamartis@redhat.com> - 6.0-65
- Zipinfo: remove the extra %c that cause invalid reads
- Zipinfo: fix the whitespace formating of the help message
Related: RHEL-59972
* Sat Jul 20 2024 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-64
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
* Sat Jan 27 2024 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-63
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Sat Jul 22 2023 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-62
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Thu Apr 13 2023 Lukáš Zaoral <lzaoral@redhat.com> - 6.0-61
- migrate to SPDX license format
* Wed Jan 25 2023 Siddhesh Poyarekar <siddhesh@redhat.com> - 6.0-60
- Fix length passed to wcstombs call (#2164068)
* Sat Jan 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-59
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Wed Nov 09 2022 Jakub Martisko <jamartis@redhat.com> - 6.0-59
- Rebuild with the -std=gnu89 flag
Resolves: rhbz#1750694
* Sat Jul 23 2022 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-58
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Sat Jan 22 2022 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-57
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
* Thu Dec 16 2021 Jakub Martisko <jamartis@redhat.com> - 6.0-56
- Update the manpage regarding the 6.0-55
* Mon Dec 13 2021 Jakub Martisko <jamartis@redhat.com> - 6.0-55
- Allow to opt-out of the zipbomb detection
* Tue Nov 09 2021 Jakub Martisko <jamartis@redhat.com> - 6.0-54
- Update the URL
* Fri Jul 23 2021 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-53
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Thu Apr 29 2021 Jakub Martisko <jamartis@redhat.com> - 6.0-52
- Sync the zipbomb false postives fixes with rhel
- zipbomb-part4 patch introduced in 6.0-51 has been renamed to part6 and part4 and part5 have been ported from rhel
Resolves: 1953565
* Thu Mar 25 2021 Jakub Martisko <jamartis@redhat.com> - 6.0-51
- Fix false positive in the zipbomb detection
Related: 1920632
* Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 6.0-50
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild