[packages/unzip] - rel 7; SECURITY: CVE-2021-4217, CVE-2022-0529, CVE-2022-0530
arekm
arekm at pld-linux.org
Sun Aug 16 22:37:51 CEST 2026
commit 6a7f58c9608e77b3db1a6a5b5f1861f924ac14c2
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Sun Aug 16 22:37:12 2026 +0200
- rel 7; SECURITY: CVE-2021-4217, CVE-2022-0529, CVE-2022-0530
Syncs the patch stack with Fedora 6.0-71
unzip-6.0-CVE-2022-0529-and-0530.patch | 170 +++++++++++++++++++++
unzip-6.0-RHEL-86228.patch | 19 +++
unzip-6.0-alt-iconv-utf8.patch | 12 +-
unzip-6.0-cve-2021-4217.patch | 39 +++++
unzip-6.0-fix-warning-messages-on-big-files.patch | 15 ++
unzip-6.0-sast.patch | 11 ++
unzip-6.0-wcstombs-fortify.patch | 11 ++
unzip-zipbomb-part7.patch | 172 ++++++++++++++++++++++
unzip-zipbomb-switch.patch | 27 +---
unzip.spec | 51 +++++--
10 files changed, 487 insertions(+), 40 deletions(-)
---
diff --git a/unzip.spec b/unzip.spec
index ee95d93..174e61c 100644
--- a/unzip.spec
+++ b/unzip.spec
@@ -1,6 +1,3 @@
-#
-# TODO: bzip2 support
-#
Summary: Unpacks .zip files such as those made by pkzip under DOS
Summary(de.UTF-8): entpackt .zip-Dateien (etwa mit pkzip unter DOS erstellte)
Summary(es.UTF-8): Descompacta archivos con extensión .zip, como los que crea pkzip en DOS
@@ -13,12 +10,11 @@ Summary(tr.UTF-8): pkzip ve benzeri programların ürettiği zip arşivlerini a
Summary(uk.UTF-8): Розпаковувач файлів .zip
Name: unzip
Version: 6.00
-Release: 6
+Release: 7
License: distributable
Group: Applications/Archiving
-Source0: ftp://ftp.info-zip.org/pub/infozip/src/%{name}60.tgz
+Source0: https://downloads.sourceforge.net/project/infozip/UnZip%206.x%20(latest)/UnZip%206.0/%{name}60.tar.gz?/%{name}60.tgz
# Source0-md5: 62b490407489521db863b523a7f86375
-#Source0: ftp://sunsite.icm.edu.pl/pub/unix/archiving/info-zip/src/%{name}552.tar.gz
Source1: http://www.mif.pg.gda.pl/homepages/ankry/man-PLD/%{name}-non-english-man-pages.tar.bz2
# Source1-md5: d7f8b0b09f6e8d89591b4dc25e335764
Patch100: unzip-opt.patch
@@ -82,11 +78,28 @@ Patch29: unzip-zipbomb-manpage.patch
Patch30: unzip-zipbomb-part4.patch
Patch31: unzip-zipbomb-part5.patch
Patch32: unzip-zipbomb-part6.patch
-Patch33: unzip-zipbomb-switch.patch
-URL: http://www.info-zip.org/
-BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
+Patch33: unzip-zipbomb-part7.patch
+Patch34: unzip-zipbomb-switch.patch
+
+# fix _FORTIFY_SOURCE abort in fnfilter()
+Patch35: unzip-6.0-wcstombs-fortify.patch
+
+# dropped byte 5 when decoding 64-bit sizes
+Patch36: unzip-6.0-fix-warning-messages-on-big-files.patch
-%define Werror_cflags %{nil}
+# strcpy() on overlapping buffers in envargs()
+Patch37: unzip-6.0-sast.patch
+
+# ignore the bogus "total number of disks" Microsoft writes into ZIP64 archives
+Patch38: unzip-6.0-RHEL-86228.patch
+
+Patch39: unzip-6.0-CVE-2022-0529-and-0530.patch
+Patch40: unzip-6.0-cve-2021-4217.patch
+URL: https://infozip.sourceforge.net/
+# unix/configure probes for it; without the BR the resulting binary silently
+# loses bzip2 (method 12) support
+BuildRequires: bzip2-devel
+BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
%description
unzip will list, test, or extract files from a ZIP archive, commonly
@@ -191,6 +204,13 @@ PKZIP та PKUNZIP від PKWARE для MS-DOS, але в багатьох ви
%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
@@ -198,6 +218,9 @@ PKZIP та PKUNZIP від PKWARE для MS-DOS, але в багатьох ви
# but successfull.
#
# NOTE: unix/configure creates flags file with guessed values
+#
+# -std=gnu89 must stay on CC, not CF_NOOPT: the probes compile with bare $CC
+# and silently misdetect fchown/lchown/opendir as missing without it
X86_OPT1=""
X86_OPT2=""
%ifarch %{ix86}
@@ -206,10 +229,10 @@ X86_OPT2="-DASM_CRC"
%endif
%{__make} -f unix/Makefile generic \
- CC="%{__cc}" \
- AS="%{__cc}" \
- CF_NOOPT="%{rpmcppflags} %{rpmcflags} -I. -Wall ${X86_OPT2} -DLARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DLARGE_FILE_SUPPORT -DUNICODE_SUPPORT -DUNICODE_WCHAR -DUNICODE_SUPPORT -DUTF8_MAYBE_NATIVE -DNO_LCHMOD -DHAVE_DIRENT_H -DHAVE_TERMIOS_H -D_MBCS -DNOMEMCPY -DIZ_HAVE_UXUIDGID" \
- AF="${X86_OPT} %{rpmldflags}" \
+ CC="%{__cc} -std=gnu89" \
+ AS="%{__cc} -std=gnu89" \
+ CF_NOOPT="%{rpmcppflags} %{rpmcflags} -I. -Wall ${X86_OPT2} -DLARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DLARGE_FILE_SUPPORT -DUNICODE_SUPPORT -DUNICODE_WCHAR -DUTF8_MAYBE_NATIVE -DNO_LCHMOD -DHAVE_DIRENT_H -DHAVE_TERMIOS_H -D_MBCS -DNOMEMCPY -DIZ_HAVE_UXUIDGID" \
+ AF="${X86_OPT1}" \
%ifarch %{ix86}
CRCA_O="crc_gcc.o" \
%endif
diff --git a/unzip-6.0-CVE-2022-0529-and-0530.patch b/unzip-6.0-CVE-2022-0529-and-0530.patch
new file mode 100644
index 0000000..2b84b96
--- /dev/null
+++ b/unzip-6.0-CVE-2022-0529-and-0530.patch
@@ -0,0 +1,170 @@
+From: Steven M. Schweda <sms at 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;
+ }
+
diff --git a/unzip-6.0-RHEL-86228.patch b/unzip-6.0-RHEL-86228.patch
new file mode 100644
index 0000000..25c2fbb
--- /dev/null
+++ b/unzip-6.0-RHEL-86228.patch
@@ -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,
diff --git a/unzip-6.0-alt-iconv-utf8.patch b/unzip-6.0-alt-iconv-utf8.patch
index b9e3777..1db3164 100644
--- a/unzip-6.0-alt-iconv-utf8.patch
+++ b/unzip-6.0-alt-iconv-utf8.patch
@@ -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\
diff --git a/unzip-6.0-cve-2021-4217.patch b/unzip-6.0-cve-2021-4217.patch
new file mode 100644
index 0000000..df2391e
--- /dev/null
+++ b/unzip-6.0-cve-2021-4217.patch
@@ -0,0 +1,39 @@
+From 731d698377dbd1f5b1b90efeb8094602ed59fc40 Mon Sep 17 00:00:00 2001
+From: Nils Bars <nils.bars at t-online.de>
+Date: Mon, 17 Jan 2022 16:53:16 +0000
+Subject: [PATCH] Fix null pointer dereference and use of uninitialized data
+
+This fixes a bug that causes use of uninitialized heap data if `readbuf` fails
+to read as many bytes as indicated by the extra field length attribute.
+Furthermore, this fixes a null pointer dereference if an archive contains an
+`EF_UNIPATH` extra field but does not have a filename set.
+
+The do_string()/fileio.c half is dropped here: unzip-6.0-valgrind.patch
+already zero-fills and truncates the short read.
+---
+ process.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/process.c b/process.c
+index d2a846e..cba2463 100644
+--- a/process.c
++++ b/process.c
+@@ -2064,10 +2064,14 @@ int getUnicodeData(__G__ ef_buf, ef_len)
+ G.unipath_checksum = makelong(offset + ef_buf);
+ offset += 4;
+
++ if (!G.filename_full) {
++ /* Check if we have a unicode extra section but no filename set */
++ return PK_ERR;
++ }
++
+ /*
+ * Compute 32-bit crc
+ */
+-
+ chksum = crc32(chksum, (uch *)(G.filename_full),
+ strlen(G.filename_full));
+
+--
+2.25.1
+
diff --git a/unzip-6.0-fix-warning-messages-on-big-files.patch b/unzip-6.0-fix-warning-messages-on-big-files.patch
new file mode 100644
index 0000000..55a115a
--- /dev/null
+++ b/unzip-6.0-fix-warning-messages-on-big-files.patch
@@ -0,0 +1,15 @@
+From: "Steven M. Schweda" <sms at 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)
diff --git a/unzip-6.0-sast.patch b/unzip-6.0-sast.patch
new file mode 100644
index 0000000..71b7cb9
--- /dev/null
+++ b/unzip-6.0-sast.patch
@@ -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;
+ }
diff --git a/unzip-6.0-wcstombs-fortify.patch b/unzip-6.0-wcstombs-fortify.patch
new file mode 100644
index 0000000..6e03cea
--- /dev/null
+++ b/unzip-6.0-wcstombs-fortify.patch
@@ -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;
diff --git a/unzip-zipbomb-part7.patch b/unzip-zipbomb-part7.patch
new file mode 100644
index 0000000..4edc152
--- /dev/null
+++ b/unzip-zipbomb-part7.patch
@@ -0,0 +1,172 @@
+From af0d07f95809653b669d88aa0f424c6d5aa48ba0 Mon Sep 17 00:00:00 2001
+From: Mark Adler <fork at 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;
diff --git a/unzip-zipbomb-switch.patch b/unzip-zipbomb-switch.patch
index c6d33c0..e355afd 100644
--- a/unzip-zipbomb-switch.patch
+++ b/unzip-zipbomb-switch.patch
@@ -137,26 +137,13 @@ index 878817d..3e58071 100644
- if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
+ if (uO.zipbomb == TRUE) {
+ if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
- /* skip over data descriptor (harder than it sounds, due to signature
- * ambiguity)
- */
-@@ -2189,16 +2196,16 @@ static int extract_or_test_member(__G) /* return PK-type error code */
- ((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 */
-+ /* if not SIG, have signature */
- )))))
-- /* skip four more bytes to account for signature */
-- shy += 4 - readbuf((char *)buf, 4);
-+ /* 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 */
-+ shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
- if (shy)
-- error = PK_ERR;
-+ error = PK_ERR;
+ // 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;
+ }
+ }
}
-
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/unzip.git/commitdiff/6a7f58c9608e77b3db1a6a5b5f1861f924ac14c2
More information about the pld-cvs-commit
mailing list