Switch to new package format
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
From 754137e70cf58a64ad524b704a86b651ba0cde07 Mon Sep 17 00:00:00 2001
|
||||
From: Petr Stodulka <[email protected]>
|
||||
Date: Wed, 14 Dec 2016 16:30:36 +0100
|
||||
Subject: [PATCH] Fix CVE-2016-9844 (rhbz#1404283)
|
||||
|
||||
Fixes buffer overflow in zipinfo in similar way like fix for
|
||||
CVE-2014-9913 provided by upstream.
|
||||
---
|
||||
zipinfo.c | 14 +++++++++++++-
|
||||
1 file changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/zipinfo.c b/zipinfo.c
|
||||
index c03620e..accca2a 100644
|
||||
--- a/zipinfo.c
|
||||
+++ b/zipinfo.c
|
||||
@@ -1984,7 +1984,19 @@ static int zi_short(__G) /* return PK-type error code */
|
||||
ush dnum=(ush)((G.crec.general_purpose_bit_flag>>1) & 3);
|
||||
methbuf[3] = dtype[dnum];
|
||||
} else if (methnum >= NUM_METHODS) { /* unknown */
|
||||
- sprintf(&methbuf[1], "%03u", G.crec.compression_method);
|
||||
+ /* 2016-12-05 SMS.
|
||||
+ * https://launchpad.net/bugs/1643750
|
||||
+ * Unexpectedly large compression methods overflow
|
||||
+ * &methbuf[]. Use the old, three-digit decimal format
|
||||
+ * for values which fit. Otherwise, sacrifice the "u",
|
||||
+ * and use four-digit hexadecimal.
|
||||
+ */
|
||||
+ if (G.crec.compression_method <= 999) {
|
||||
+ sprintf( &methbuf[ 1], "%03u", G.crec.compression_method);
|
||||
+ } else {
|
||||
+ sprintf( &methbuf[ 0], "%04X", G.crec.compression_method);
|
||||
+ }
|
||||
+
|
||||
}
|
||||
|
||||
for (k = 0; k < 15; ++k)
|
||||
--
|
||||
2.5.5
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
From: Steven M. Schweda <[email protected]>
|
||||
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,9 +1949,10 @@
|
||||
ef_len - EB_HEADSIZE));
|
||||
break;
|
||||
}
|
||||
+
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
From 06d1b08aef94984256cad3c5a54cedb10295681f Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Martisko <[email protected]>
|
||||
Date: Thu, 8 Nov 2018 09:31:18 +0100
|
||||
Subject: [PATCH] Possible unterminated string fix
|
||||
|
||||
---
|
||||
unix/unix.c | 4 +++-
|
||||
unix/unxcfg.h | 2 +-
|
||||
unzip.c | 12 ++++++++----
|
||||
zipinfo.c | 12 ++++++++----
|
||||
4 files changed, 20 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/unix/unix.c b/unix/unix.c
|
||||
index 59b622d..cd57f80 100644
|
||||
--- a/unix/unix.c
|
||||
+++ b/unix/unix.c
|
||||
@@ -1945,7 +1945,9 @@ void init_conversion_charsets()
|
||||
for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++)
|
||||
if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) {
|
||||
strncpy(OEM_CP, dos_charset_map[i].archive_charset,
|
||||
- sizeof(OEM_CP));
|
||||
+ MAX_CP_NAME - 1);
|
||||
+
|
||||
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
diff --git a/unix/unxcfg.h b/unix/unxcfg.h
|
||||
index 8729de2..9ee8cfe 100644
|
||||
--- a/unix/unxcfg.h
|
||||
+++ b/unix/unxcfg.h
|
||||
@@ -228,7 +228,7 @@ typedef struct stat z_stat;
|
||||
/* and notfirstcall are used by do_wild(). */
|
||||
|
||||
|
||||
-#define MAX_CP_NAME 25
|
||||
+#define MAX_CP_NAME 25 + 1
|
||||
|
||||
#ifdef SETLOCALE
|
||||
# undef SETLOCALE
|
||||
diff --git a/unzip.c b/unzip.c
|
||||
index 2d94a38..a485f2b 100644
|
||||
--- a/unzip.c
|
||||
+++ b/unzip.c
|
||||
@@ -1561,7 +1561,8 @@ int uz_opts(__G__ pargc, pargv)
|
||||
"error: a valid character encoding should follow the -I argument"));
|
||||
return(PK_PARAM);
|
||||
}
|
||||
- strncpy(ISO_CP, s, sizeof(ISO_CP));
|
||||
+ strncpy(ISO_CP, s, MAX_CP_NAME - 1);
|
||||
+ ISO_CP[MAX_CP_NAME - 1] = '\0';
|
||||
} else { /* -I charset */
|
||||
++argv;
|
||||
if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
|
||||
@@ -1570,7 +1571,8 @@ int uz_opts(__G__ pargc, pargv)
|
||||
return(PK_PARAM);
|
||||
}
|
||||
s = *argv;
|
||||
- strncpy(ISO_CP, s, sizeof(ISO_CP));
|
||||
+ strncpy(ISO_CP, s, MAX_CP_NAME - 1);
|
||||
+ ISO_CP[MAX_CP_NAME - 1] = '\0';
|
||||
}
|
||||
while(*(++s)); /* No params straight after charset name */
|
||||
}
|
||||
@@ -1665,7 +1667,8 @@ int uz_opts(__G__ pargc, pargv)
|
||||
"error: a valid character encoding should follow the -I argument"));
|
||||
return(PK_PARAM);
|
||||
}
|
||||
- strncpy(OEM_CP, s, sizeof(OEM_CP));
|
||||
+ strncpy(OEM_CP, s, MAX_CP_NAME - 1);
|
||||
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
|
||||
} else { /* -O charset */
|
||||
++argv;
|
||||
if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
|
||||
@@ -1674,7 +1677,8 @@ int uz_opts(__G__ pargc, pargv)
|
||||
return(PK_PARAM);
|
||||
}
|
||||
s = *argv;
|
||||
- strncpy(OEM_CP, s, sizeof(OEM_CP));
|
||||
+ strncpy(OEM_CP, s, MAX_CP_NAME - 1);
|
||||
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
|
||||
}
|
||||
while(*(++s)); /* No params straight after charset name */
|
||||
}
|
||||
diff --git a/zipinfo.c b/zipinfo.c
|
||||
index accca2a..cb7e08d 100644
|
||||
--- a/zipinfo.c
|
||||
+++ b/zipinfo.c
|
||||
@@ -519,7 +519,8 @@ int zi_opts(__G__ pargc, pargv)
|
||||
"error: a valid character encoding should follow the -I argument"));
|
||||
return(PK_PARAM);
|
||||
}
|
||||
- strncpy(ISO_CP, s, sizeof(ISO_CP));
|
||||
+ strncpy(ISO_CP, s, MAX_CP_NAME - 1);
|
||||
+ ISO_CP[MAX_CP_NAME - 1] = '\0';
|
||||
} else { /* -I charset */
|
||||
++argv;
|
||||
if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
|
||||
@@ -528,7 +529,8 @@ int zi_opts(__G__ pargc, pargv)
|
||||
return(PK_PARAM);
|
||||
}
|
||||
s = *argv;
|
||||
- strncpy(ISO_CP, s, sizeof(ISO_CP));
|
||||
+ strncpy(ISO_CP, s, MAX_CP_NAME - 1);
|
||||
+ ISO_CP[MAX_CP_NAME - 1] = '\0';
|
||||
}
|
||||
while(*(++s)); /* No params straight after charset name */
|
||||
}
|
||||
@@ -568,7 +570,8 @@ int zi_opts(__G__ pargc, pargv)
|
||||
"error: a valid character encoding should follow the -I argument"));
|
||||
return(PK_PARAM);
|
||||
}
|
||||
- strncpy(OEM_CP, s, sizeof(OEM_CP));
|
||||
+ strncpy(OEM_CP, s, MAX_CP_NAME - 1);
|
||||
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
|
||||
} else { /* -O charset */
|
||||
++argv;
|
||||
if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
|
||||
@@ -577,7 +580,8 @@ int zi_opts(__G__ pargc, pargv)
|
||||
return(PK_PARAM);
|
||||
}
|
||||
s = *argv;
|
||||
- strncpy(OEM_CP, s, sizeof(OEM_CP));
|
||||
+ strncpy(OEM_CP, s, MAX_CP_NAME - 1);
|
||||
+ OEM_CP[MAX_CP_NAME - 1] = '\0';
|
||||
}
|
||||
while(*(++s)); /* No params straight after charset name */
|
||||
}
|
||||
--
|
||||
2.14.5
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
From ca0212ba19b64488b9e8459a762c11ecd6e7d0bd Mon Sep 17 00:00:00 2001
|
||||
From: Petr Stodulka <[email protected]>
|
||||
Date: Tue, 24 Nov 2015 17:56:11 +0100
|
||||
Subject: [PATCH] print correctly non-ascii filenames
|
||||
|
||||
---
|
||||
extract.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++--------------
|
||||
unzpriv.h | 7 ++
|
||||
2 files changed, 233 insertions(+), 63 deletions(-)
|
||||
|
||||
diff --git a/extract.c b/extract.c
|
||||
index 0ee4e93..741b7e0 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -2648,8 +2648,21 @@ static void set_deferred_symlink(__G__ slnk_entry)
|
||||
} /* end function set_deferred_symlink() */
|
||||
#endif /* SYMLINKS */
|
||||
|
||||
+/*
|
||||
+ * If Unicode is supported, assume we have what we need to do this
|
||||
+ * check using wide characters, avoiding MBCS issues.
|
||||
+ */
|
||||
|
||||
-
|
||||
+#ifndef UZ_FNFILTER_REPLACECHAR
|
||||
+ /* A convenient choice for the replacement of unprintable char codes is
|
||||
+ * the "single char wildcard", as this character is quite unlikely to
|
||||
+ * appear in filenames by itself. The following default definition
|
||||
+ * sets the replacement char to a question mark as the most common
|
||||
+ * "single char wildcard"; this setting should be overridden in the
|
||||
+ * appropiate system-specific configuration header when needed.
|
||||
+ */
|
||||
+# define UZ_FNFILTER_REPLACECHAR '?'
|
||||
+#endif
|
||||
|
||||
/*************************/
|
||||
/* Function fnfilter() */ /* here instead of in list.c for SFX */
|
||||
@@ -2661,48 +2674,168 @@ char *fnfilter(raw, space, size) /* convert name to safely printable form */
|
||||
extent size;
|
||||
{
|
||||
#ifndef NATIVE /* ASCII: filter ANSI escape codes, etc. */
|
||||
- ZCONST uch *r=(ZCONST uch *)raw;
|
||||
+ ZCONST uch *r; // =(ZCONST uch *)raw;
|
||||
uch *s=space;
|
||||
uch *slim=NULL;
|
||||
uch *se=NULL;
|
||||
int have_overflow = FALSE;
|
||||
|
||||
- if (size > 0) {
|
||||
- slim = space + size
|
||||
-#ifdef _MBCS
|
||||
- - (MB_CUR_MAX - 1)
|
||||
-#endif
|
||||
- - 4;
|
||||
+# if defined( UNICODE_SUPPORT) && defined( _MBCS)
|
||||
+/* If Unicode support is enabled, and we have multi-byte characters,
|
||||
+ * then do the isprint() checks by first converting to wide characters
|
||||
+ * and checking those. This avoids our having to parse multi-byte
|
||||
+ * characters for ourselves. After the wide-char replacements have been
|
||||
+ * made, the wide string is converted back to the local character set.
|
||||
+ */
|
||||
+ wchar_t *wstring; /* wchar_t version of raw */
|
||||
+ size_t wslen; /* length of wstring */
|
||||
+ wchar_t *wostring; /* wchar_t version of output string */
|
||||
+ size_t woslen; /* length of wostring */
|
||||
+ char *newraw; /* new raw */
|
||||
+
|
||||
+ /* 2012-11-06 SMS.
|
||||
+ * Changed to check the value returned by mbstowcs(), and bypass the
|
||||
+ * Unicode processing if it fails. This seems to fix a problem
|
||||
+ * reported in the SourceForge forum, but it's not clear that we
|
||||
+ * should be doing any Unicode processing without some evidence that
|
||||
+ * the name actually is Unicode. (Check bit 11 in the flags before
|
||||
+ * coming here?)
|
||||
+ * http://sourceforge.net/p/infozip/bugs/40/
|
||||
+ */
|
||||
+
|
||||
+ if (MB_CUR_MAX <= 1)
|
||||
+ {
|
||||
+ /* There's no point to converting multi-byte chars if there are
|
||||
+ * no multi-byte chars.
|
||||
+ */
|
||||
+ wslen = (size_t)-1;
|
||||
}
|
||||
- while (*r) {
|
||||
- if (size > 0 && s >= slim && se == NULL) {
|
||||
- se = s;
|
||||
+ else
|
||||
+ {
|
||||
+ /* Get Unicode wide character count (for storage allocation). */
|
||||
+ wslen = mbstowcs( NULL, raw, 0);
|
||||
+ }
|
||||
+
|
||||
+ if (wslen != (size_t)-1)
|
||||
+ {
|
||||
+ /* Apparently valid Unicode. Allocate wide-char storage. */
|
||||
+ wstring = (wchar_t *)malloc((wslen + 1) * sizeof(wchar_t));
|
||||
+ if (wstring == NULL) {
|
||||
+ strcpy( (char *)space, raw);
|
||||
+ return (char *)space;
|
||||
}
|
||||
-#ifdef QDOS
|
||||
- if (qlflag & 2) {
|
||||
- if (*r == '/' || *r == '.') {
|
||||
+ wostring = (wchar_t *)malloc(2 * (wslen + 1) * sizeof(wchar_t));
|
||||
+ if (wostring == NULL) {
|
||||
+ free(wstring);
|
||||
+ strcpy( (char *)space, raw);
|
||||
+ return (char *)space;
|
||||
+ }
|
||||
+
|
||||
+ /* Convert the multi-byte Unicode to wide chars. */
|
||||
+ wslen = mbstowcs(wstring, raw, wslen + 1);
|
||||
+
|
||||
+ /* Filter the wide-character string. */
|
||||
+ fnfilterw( wstring, wostring, (2 * (wslen + 1) * sizeof(wchar_t)));
|
||||
+
|
||||
+ /* Convert filtered wide chars back to multi-byte. */
|
||||
+ woslen = wcstombs( NULL, wostring, 0);
|
||||
+ if ((newraw = malloc(woslen + 1)) == NULL) {
|
||||
+ free(wstring);
|
||||
+ free(wostring);
|
||||
+ strcpy( (char *)space, raw);
|
||||
+ return (char *)space;
|
||||
+ }
|
||||
+ woslen = wcstombs( newraw, wostring, (woslen * MB_CUR_MAX) + 1);
|
||||
+
|
||||
+ if (size > 0) {
|
||||
+ slim = space + size - 4;
|
||||
+ }
|
||||
+ r = (ZCONST uch *)newraw;
|
||||
+ while (*r) {
|
||||
+ if (size > 0 && s >= slim && se == NULL) {
|
||||
+ se = s;
|
||||
+ }
|
||||
+# ifdef QDOS
|
||||
+ if (qlflag & 2) {
|
||||
+ if (*r == '/' || *r == '.') {
|
||||
+ if (se != NULL && (s > (space + (size-3)))) {
|
||||
+ have_overflow = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ ++r;
|
||||
+ *s++ = '_';
|
||||
+ continue;
|
||||
+ }
|
||||
+ } else
|
||||
+# endif
|
||||
+ {
|
||||
if (se != NULL && (s > (space + (size-3)))) {
|
||||
have_overflow = TRUE;
|
||||
break;
|
||||
}
|
||||
- ++r;
|
||||
- *s++ = '_';
|
||||
- continue;
|
||||
+ *s++ = *r++;
|
||||
}
|
||||
- } else
|
||||
+ }
|
||||
+ if (have_overflow) {
|
||||
+ strcpy((char *)se, "...");
|
||||
+ } else {
|
||||
+ *s = '\0';
|
||||
+ }
|
||||
+
|
||||
+ free(wstring);
|
||||
+ free(wostring);
|
||||
+ free(newraw);
|
||||
+ }
|
||||
+ else
|
||||
+# endif /* defined( UNICODE_SUPPORT) && defined( _MBCS) */
|
||||
+ {
|
||||
+ /* No Unicode support, or apparently invalid Unicode. */
|
||||
+ r = (ZCONST uch *)raw;
|
||||
+
|
||||
+ if (size > 0) {
|
||||
+ slim = space + size
|
||||
+#ifdef _MBCS
|
||||
+ - (MB_CUR_MAX - 1)
|
||||
+#endif
|
||||
+ - 4;
|
||||
+ }
|
||||
+ while (*r) {
|
||||
+ if (size > 0 && s >= slim && se == NULL) {
|
||||
+ se = s;
|
||||
+ }
|
||||
+#ifdef QDOS
|
||||
+ if (qlflag & 2) {
|
||||
+ if (*r == '/' || *r == '.') {
|
||||
+ if (se != NULL && (s > (space + (size-3)))) {
|
||||
+ have_overflow = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ ++r;
|
||||
+ *s++ = '_';
|
||||
+ continue;
|
||||
+ }
|
||||
+ } else
|
||||
#endif
|
||||
#ifdef HAVE_WORKING_ISPRINT
|
||||
-# ifndef UZ_FNFILTER_REPLACECHAR
|
||||
- /* A convenient choice for the replacement of unprintable char codes is
|
||||
- * the "single char wildcard", as this character is quite unlikely to
|
||||
- * appear in filenames by itself. The following default definition
|
||||
- * sets the replacement char to a question mark as the most common
|
||||
- * "single char wildcard"; this setting should be overridden in the
|
||||
- * appropiate system-specific configuration header when needed.
|
||||
- */
|
||||
-# define UZ_FNFILTER_REPLACECHAR '?'
|
||||
-# endif
|
||||
- if (!isprint(*r)) {
|
||||
+ if (!isprint(*r)) {
|
||||
+ if (*r < 32) {
|
||||
+ /* ASCII control codes are escaped as "^{letter}". */
|
||||
+ if (se != NULL && (s > (space + (size-4)))) {
|
||||
+ have_overflow = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ *s++ = '^', *s++ = (uch)(64 + *r++);
|
||||
+ } else {
|
||||
+ /* Other unprintable codes are replaced by the
|
||||
+ * placeholder character. */
|
||||
+ if (se != NULL && (s > (space + (size-3)))) {
|
||||
+ have_overflow = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ *s++ = UZ_FNFILTER_REPLACECHAR;
|
||||
+ INCSTR(r);
|
||||
+ }
|
||||
+#else /* !HAVE_WORKING_ISPRINT */
|
||||
if (*r < 32) {
|
||||
/* ASCII control codes are escaped as "^{letter}". */
|
||||
if (se != NULL && (s > (space + (size-4)))) {
|
||||
@@ -2710,47 +2843,30 @@ char *fnfilter(raw, space, size) /* convert name to safely printable form */
|
||||
break;
|
||||
}
|
||||
*s++ = '^', *s++ = (uch)(64 + *r++);
|
||||
+#endif /* ?HAVE_WORKING_ISPRINT */
|
||||
} else {
|
||||
- /* Other unprintable codes are replaced by the
|
||||
- * placeholder character. */
|
||||
+#ifdef _MBCS
|
||||
+ unsigned i = CLEN(r);
|
||||
+ if (se != NULL && (s > (space + (size-i-2)))) {
|
||||
+ have_overflow = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ for (; i > 0; i--)
|
||||
+ *s++ = *r++;
|
||||
+#else
|
||||
if (se != NULL && (s > (space + (size-3)))) {
|
||||
have_overflow = TRUE;
|
||||
break;
|
||||
}
|
||||
- *s++ = UZ_FNFILTER_REPLACECHAR;
|
||||
- INCSTR(r);
|
||||
- }
|
||||
-#else /* !HAVE_WORKING_ISPRINT */
|
||||
- if (*r < 32) {
|
||||
- /* ASCII control codes are escaped as "^{letter}". */
|
||||
- if (se != NULL && (s > (space + (size-4)))) {
|
||||
- have_overflow = TRUE;
|
||||
- break;
|
||||
- }
|
||||
- *s++ = '^', *s++ = (uch)(64 + *r++);
|
||||
-#endif /* ?HAVE_WORKING_ISPRINT */
|
||||
- } else {
|
||||
-#ifdef _MBCS
|
||||
- unsigned i = CLEN(r);
|
||||
- if (se != NULL && (s > (space + (size-i-2)))) {
|
||||
- have_overflow = TRUE;
|
||||
- break;
|
||||
- }
|
||||
- for (; i > 0; i--)
|
||||
*s++ = *r++;
|
||||
-#else
|
||||
- if (se != NULL && (s > (space + (size-3)))) {
|
||||
- have_overflow = TRUE;
|
||||
- break;
|
||||
- }
|
||||
- *s++ = *r++;
|
||||
#endif
|
||||
- }
|
||||
- }
|
||||
- if (have_overflow) {
|
||||
- strcpy((char *)se, "...");
|
||||
- } else {
|
||||
- *s = '\0';
|
||||
+ }
|
||||
+ }
|
||||
+ if (have_overflow) {
|
||||
+ strcpy((char *)se, "...");
|
||||
+ } else {
|
||||
+ *s = '\0';
|
||||
+ }
|
||||
}
|
||||
|
||||
#ifdef WINDLL
|
||||
@@ -2772,6 +2888,53 @@ char *fnfilter(raw, space, size) /* convert name to safely printable form */
|
||||
} /* end function fnfilter() */
|
||||
|
||||
|
||||
+#if defined( UNICODE_SUPPORT) && defined( _MBCS)
|
||||
+
|
||||
+/****************************/
|
||||
+/* Function fnfilter[w]() */ /* (Here instead of in list.c for SFX.) */
|
||||
+/****************************/
|
||||
+
|
||||
+/* fnfilterw() - Convert wide name to safely printable form. */
|
||||
+
|
||||
+/* fnfilterw() - Convert wide-character name to safely printable form. */
|
||||
+
|
||||
+wchar_t *fnfilterw( src, dst, siz)
|
||||
+ ZCONST wchar_t *src; /* Pointer to source char (string). */
|
||||
+ wchar_t *dst; /* Pointer to destination char (string). */
|
||||
+ extent siz; /* Not used (!). */
|
||||
+{
|
||||
+ wchar_t *dsx = dst;
|
||||
+
|
||||
+ /* Filter the wide chars. */
|
||||
+ while (*src)
|
||||
+ {
|
||||
+ if (iswprint( *src))
|
||||
+ {
|
||||
+ /* Printable code. Copy it. */
|
||||
+ *dst++ = *src;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* Unprintable code. Substitute something printable for it. */
|
||||
+ if (*src < 32)
|
||||
+ {
|
||||
+ /* Replace ASCII control code with "^{letter}". */
|
||||
+ *dst++ = (wchar_t)'^';
|
||||
+ *dst++ = (wchar_t)(64 + *src);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* Replace other unprintable code with the placeholder. */
|
||||
+ *dst++ = (wchar_t)UZ_FNFILTER_REPLACECHAR;
|
||||
+ }
|
||||
+ }
|
||||
+ src++;
|
||||
+ }
|
||||
+ *dst = (wchar_t)0; /* NUL-terminate the destination string. */
|
||||
+ return dsx;
|
||||
+} /* fnfilterw(). */
|
||||
+
|
||||
+#endif /* defined( UNICODE_SUPPORT) && defined( _MBCS) */
|
||||
|
||||
|
||||
#ifdef SET_DIR_ATTRIB
|
||||
diff --git a/unzpriv.h b/unzpriv.h
|
||||
index 22d3923..e48a652 100644
|
||||
--- a/unzpriv.h
|
||||
+++ b/unzpriv.h
|
||||
@@ -1212,6 +1212,7 @@
|
||||
# ifdef UNICODE_WCHAR
|
||||
# if !(defined(_WIN32_WCE) || defined(POCKET_UNZIP))
|
||||
# include <wchar.h>
|
||||
+# include <wctype.h>
|
||||
# endif
|
||||
# endif
|
||||
# ifndef _MBCS /* no need to include <locale.h> twice, see below */
|
||||
@@ -2410,6 +2411,12 @@ int memflush OF((__GPRO__ ZCONST uch *rawbuf, ulg size));
|
||||
char *fnfilter OF((ZCONST char *raw, uch *space,
|
||||
extent size));
|
||||
|
||||
+# if defined( UNICODE_SUPPORT) && defined( _MBCS)
|
||||
+wchar_t *fnfilterw OF((ZCONST wchar_t *src, wchar_t *dst,
|
||||
+ extent siz));
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
/*---------------------------------------------------------------------------
|
||||
Decompression functions:
|
||||
---------------------------------------------------------------------------*/
|
||||
--
|
||||
2.4.3
|
||||
|
||||
@@ -0,0 +1,398 @@
|
||||
From: Giovanni Scafora <giovanni.archlinux.org>
|
||||
Subject: unzip files encoded with non-latin, non-unicode file names
|
||||
Last-Update: 2015-02-11
|
||||
|
||||
Updated 2015-02-11 by Marc Deslauriers <[email protected]>
|
||||
to fix buffer overflow in charset_to_intern()
|
||||
|
||||
Index: unzip-6.0/unix/unix.c
|
||||
===================================================================
|
||||
--- unzip-6.0.orig/unix/unix.c 2015-02-11 08:46:43.675324290 -0500
|
||||
+++ unzip-6.0/unix/unix.c 2015-02-11 09:18:04.902081319 -0500
|
||||
@@ -30,6 +30,9 @@
|
||||
#define UNZIP_INTERNAL
|
||||
#include "unzip.h"
|
||||
|
||||
+#include <iconv.h>
|
||||
+#include <langinfo.h>
|
||||
+
|
||||
#ifdef SCO_XENIX
|
||||
# define SYSNDIR
|
||||
#else /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
|
||||
@@ -1874,3 +1877,102 @@
|
||||
}
|
||||
}
|
||||
#endif /* QLZIP */
|
||||
+
|
||||
+
|
||||
+typedef struct {
|
||||
+ char *local_charset;
|
||||
+ char *archive_charset;
|
||||
+} CHARSET_MAP;
|
||||
+
|
||||
+/* A mapping of local <-> archive charsets used by default to convert filenames
|
||||
+ * of DOS/Windows Zip archives. Currently very basic. */
|
||||
+static CHARSET_MAP dos_charset_map[] = {
|
||||
+ { "ANSI_X3.4-1968", "CP850" },
|
||||
+ { "ISO-8859-1", "CP850" },
|
||||
+ { "CP1252", "CP850" },
|
||||
+ { "UTF-8", "CP866" },
|
||||
+ { "KOI8-R", "CP866" },
|
||||
+ { "KOI8-U", "CP866" },
|
||||
+ { "ISO-8859-5", "CP866" }
|
||||
+};
|
||||
+
|
||||
+char OEM_CP[MAX_CP_NAME] = "";
|
||||
+char ISO_CP[MAX_CP_NAME] = "";
|
||||
+
|
||||
+/* Try to guess the default value of OEM_CP based on the current locale.
|
||||
+ * ISO_CP is left alone for now. */
|
||||
+void init_conversion_charsets()
|
||||
+{
|
||||
+ const char *local_charset;
|
||||
+ int i;
|
||||
+
|
||||
+ /* Make a guess only if OEM_CP not already set. */
|
||||
+ if(*OEM_CP == '\0') {
|
||||
+ local_charset = nl_langinfo(CODESET);
|
||||
+ for(i = 0; i < sizeof(dos_charset_map)/sizeof(CHARSET_MAP); i++)
|
||||
+ if(!strcasecmp(local_charset, dos_charset_map[i].local_charset)) {
|
||||
+ strncpy(OEM_CP, dos_charset_map[i].archive_charset,
|
||||
+ sizeof(OEM_CP));
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Convert a string from one encoding to the current locale using iconv().
|
||||
+ * Be as non-intrusive as possible. If error is encountered during covertion
|
||||
+ * just leave the string intact. */
|
||||
+static void charset_to_intern(char *string, char *from_charset)
|
||||
+{
|
||||
+ iconv_t cd;
|
||||
+ char *s,*d, *buf;
|
||||
+ size_t slen, dlen, buflen;
|
||||
+ const char *local_charset;
|
||||
+
|
||||
+ if(*from_charset == '\0')
|
||||
+ return;
|
||||
+
|
||||
+ buf = NULL;
|
||||
+ local_charset = nl_langinfo(CODESET);
|
||||
+
|
||||
+ if((cd = iconv_open(local_charset, from_charset)) == (iconv_t)-1)
|
||||
+ return;
|
||||
+
|
||||
+ slen = strlen(string);
|
||||
+ s = string;
|
||||
+
|
||||
+ /* Make sure OUTBUFSIZ + 1 never ends up smaller than FILNAMSIZ
|
||||
+ * as this function also gets called with G.outbuf in fileio.c
|
||||
+ */
|
||||
+ buflen = FILNAMSIZ;
|
||||
+ if (OUTBUFSIZ + 1 < FILNAMSIZ)
|
||||
+ {
|
||||
+ buflen = OUTBUFSIZ + 1;
|
||||
+ }
|
||||
+
|
||||
+ d = buf = malloc(buflen);
|
||||
+ if(!d)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ bzero(buf,buflen);
|
||||
+ dlen = buflen - 1;
|
||||
+
|
||||
+ if(iconv(cd, &s, &slen, &d, &dlen) == (size_t)-1)
|
||||
+ goto cleanup;
|
||||
+ strncpy(string, buf, buflen);
|
||||
+
|
||||
+ cleanup:
|
||||
+ free(buf);
|
||||
+ iconv_close(cd);
|
||||
+}
|
||||
+
|
||||
+/* Convert a string from OEM_CP to the current locale charset. */
|
||||
+inline void oem_intern(char *string)
|
||||
+{
|
||||
+ charset_to_intern(string, OEM_CP);
|
||||
+}
|
||||
+
|
||||
+/* Convert a string from ISO_CP to the current locale charset. */
|
||||
+inline void iso_intern(char *string)
|
||||
+{
|
||||
+ charset_to_intern(string, ISO_CP);
|
||||
+}
|
||||
Index: unzip-6.0/unix/unxcfg.h
|
||||
===================================================================
|
||||
--- unzip-6.0.orig/unix/unxcfg.h 2015-02-11 08:46:43.675324290 -0500
|
||||
+++ unzip-6.0/unix/unxcfg.h 2015-02-11 08:46:43.671324260 -0500
|
||||
@@ -228,4 +228,30 @@
|
||||
/* wild_dir, dirname, wildname, matchname[], dirnamelen, have_dirname, */
|
||||
/* and notfirstcall are used by do_wild(). */
|
||||
|
||||
+
|
||||
+#define MAX_CP_NAME 25
|
||||
+
|
||||
+#ifdef SETLOCALE
|
||||
+# undef SETLOCALE
|
||||
+#endif
|
||||
+#define SETLOCALE(category, locale) setlocale(category, locale)
|
||||
+#include <locale.h>
|
||||
+
|
||||
+#ifdef _ISO_INTERN
|
||||
+# undef _ISO_INTERN
|
||||
+#endif
|
||||
+#define _ISO_INTERN(str1) iso_intern(str1)
|
||||
+
|
||||
+#ifdef _OEM_INTERN
|
||||
+# undef _OEM_INTERN
|
||||
+#endif
|
||||
+#ifndef IZ_OEM2ISO_ARRAY
|
||||
+# define IZ_OEM2ISO_ARRAY
|
||||
+#endif
|
||||
+#define _OEM_INTERN(str1) oem_intern(str1)
|
||||
+
|
||||
+void iso_intern(char *);
|
||||
+void oem_intern(char *);
|
||||
+void init_conversion_charsets(void);
|
||||
+
|
||||
#endif /* !__unxcfg_h */
|
||||
Index: unzip-6.0/unzip.c
|
||||
===================================================================
|
||||
--- unzip-6.0.orig/unzip.c 2015-02-11 08:46:43.675324290 -0500
|
||||
+++ unzip-6.0/unzip.c 2015-02-11 08:46:43.675324290 -0500
|
||||
@@ -327,11 +327,21 @@
|
||||
-2 just filenames but allow -h/-t/-z -l long Unix \"ls -l\" format\n\
|
||||
-v verbose, multi-page format\n";
|
||||
|
||||
+#ifndef 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 -T print file times in sortable decimal format\
|
||||
\n -C be case-insensitive %s\
|
||||
-x exclude filenames that follow from listing\n";
|
||||
+#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 -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";
|
||||
+#endif /* !UNIX */
|
||||
#ifdef MORE
|
||||
static ZCONST char Far ZipInfoUsageLine4[] =
|
||||
" -M page output through built-in \"more\"\n";
|
||||
@@ -664,6 +674,17 @@
|
||||
-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";
|
||||
+#elif (defined UNIX)
|
||||
+static ZCONST char Far UnzipUsageLine4[] = "\
|
||||
+modifiers:\n\
|
||||
+ -n never overwrite existing files -q quiet mode (-qq => quieter)\n\
|
||||
+ -o overwrite files WITHOUT prompting -a auto-convert any text files\n\
|
||||
+ -j junk paths (do not make directories) -aa treat ALL files as text\n\
|
||||
+ -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";
|
||||
#else /* !VMS */
|
||||
static ZCONST char Far UnzipUsageLine4[] = "\
|
||||
modifiers:\n\
|
||||
@@ -802,6 +823,10 @@
|
||||
#endif /* UNICODE_SUPPORT */
|
||||
|
||||
|
||||
+#ifdef UNIX
|
||||
+ init_conversion_charsets();
|
||||
+#endif
|
||||
+
|
||||
#if (defined(__IBMC__) && defined(__DEBUG_ALLOC__))
|
||||
extern void DebugMalloc(void);
|
||||
|
||||
@@ -1335,6 +1360,11 @@
|
||||
argc = *pargc;
|
||||
argv = *pargv;
|
||||
|
||||
+#ifdef UNIX
|
||||
+ extern char OEM_CP[MAX_CP_NAME];
|
||||
+ extern char ISO_CP[MAX_CP_NAME];
|
||||
+#endif
|
||||
+
|
||||
while (++argv, (--argc > 0 && *argv != NULL && **argv == '-')) {
|
||||
s = *argv + 1;
|
||||
while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */
|
||||
@@ -1516,6 +1546,35 @@
|
||||
}
|
||||
break;
|
||||
#endif /* MACOS */
|
||||
+#ifdef UNIX
|
||||
+ case ('I'):
|
||||
+ if (negative) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: encodings can't be negated"));
|
||||
+ return(PK_PARAM);
|
||||
+ } else {
|
||||
+ if(*s) { /* Handle the -Icharset case */
|
||||
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
|
||||
+ if(*s == '-') {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: a valid character encoding should follow the -I argument"));
|
||||
+ return(PK_PARAM);
|
||||
+ }
|
||||
+ strncpy(ISO_CP, s, sizeof(ISO_CP));
|
||||
+ } else { /* -I charset */
|
||||
+ ++argv;
|
||||
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: a valid character encoding should follow the -I argument"));
|
||||
+ return(PK_PARAM);
|
||||
+ }
|
||||
+ s = *argv;
|
||||
+ strncpy(ISO_CP, s, sizeof(ISO_CP));
|
||||
+ }
|
||||
+ while(*(++s)); /* No params straight after charset name */
|
||||
+ }
|
||||
+ break;
|
||||
+#endif /* ?UNIX */
|
||||
case ('j'): /* junk pathnames/directory structure */
|
||||
if (negative)
|
||||
uO.jflag = FALSE, negative = 0;
|
||||
@@ -1591,6 +1650,35 @@
|
||||
} else
|
||||
++uO.overwrite_all;
|
||||
break;
|
||||
+#ifdef UNIX
|
||||
+ case ('O'):
|
||||
+ if (negative) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: encodings can't be negated"));
|
||||
+ return(PK_PARAM);
|
||||
+ } else {
|
||||
+ if(*s) { /* Handle the -Ocharset case */
|
||||
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
|
||||
+ if(*s == '-') {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: a valid character encoding should follow the -I argument"));
|
||||
+ return(PK_PARAM);
|
||||
+ }
|
||||
+ strncpy(OEM_CP, s, sizeof(OEM_CP));
|
||||
+ } else { /* -O charset */
|
||||
+ ++argv;
|
||||
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: a valid character encoding should follow the -O argument"));
|
||||
+ return(PK_PARAM);
|
||||
+ }
|
||||
+ s = *argv;
|
||||
+ strncpy(OEM_CP, s, sizeof(OEM_CP));
|
||||
+ }
|
||||
+ while(*(++s)); /* No params straight after charset name */
|
||||
+ }
|
||||
+ break;
|
||||
+#endif /* ?UNIX */
|
||||
case ('p'): /* pipes: extract to stdout, no messages */
|
||||
if (negative) {
|
||||
uO.cflag = FALSE;
|
||||
Index: unzip-6.0/unzpriv.h
|
||||
===================================================================
|
||||
--- unzip-6.0.orig/unzpriv.h 2015-02-11 08:46:43.675324290 -0500
|
||||
+++ unzip-6.0/unzpriv.h 2015-02-11 08:46:43.675324290 -0500
|
||||
@@ -3008,7 +3008,7 @@
|
||||
!(((islochdr) || (isuxatt)) && \
|
||||
((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
|
||||
(hostnum) == FS_HPFS_ || \
|
||||
- ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
|
||||
+ ((hostnum) == FS_NTFS_ /* && (hostver) == 50 */ )) { \
|
||||
_OEM_INTERN((string)); \
|
||||
} else { \
|
||||
_ISO_INTERN((string)); \
|
||||
Index: unzip-6.0/zipinfo.c
|
||||
===================================================================
|
||||
--- unzip-6.0.orig/zipinfo.c 2015-02-11 08:46:43.675324290 -0500
|
||||
+++ unzip-6.0/zipinfo.c 2015-02-11 08:46:43.675324290 -0500
|
||||
@@ -457,6 +457,10 @@
|
||||
int tflag_slm=TRUE, tflag_2v=FALSE;
|
||||
int explicit_h=FALSE, explicit_t=FALSE;
|
||||
|
||||
+#ifdef UNIX
|
||||
+ extern char OEM_CP[MAX_CP_NAME];
|
||||
+ extern char ISO_CP[MAX_CP_NAME];
|
||||
+#endif
|
||||
|
||||
#ifdef MACOS
|
||||
uO.lflag = LFLAG; /* reset default on each call */
|
||||
@@ -501,6 +505,35 @@
|
||||
uO.lflag = 0;
|
||||
}
|
||||
break;
|
||||
+#ifdef UNIX
|
||||
+ case ('I'):
|
||||
+ if (negative) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: encodings can't be negated"));
|
||||
+ return(PK_PARAM);
|
||||
+ } else {
|
||||
+ if(*s) { /* Handle the -Icharset case */
|
||||
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
|
||||
+ if(*s == '-') {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: a valid character encoding should follow the -I argument"));
|
||||
+ return(PK_PARAM);
|
||||
+ }
|
||||
+ strncpy(ISO_CP, s, sizeof(ISO_CP));
|
||||
+ } else { /* -I charset */
|
||||
+ ++argv;
|
||||
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: a valid character encoding should follow the -I argument"));
|
||||
+ return(PK_PARAM);
|
||||
+ }
|
||||
+ s = *argv;
|
||||
+ strncpy(ISO_CP, s, sizeof(ISO_CP));
|
||||
+ }
|
||||
+ while(*(++s)); /* No params straight after charset name */
|
||||
+ }
|
||||
+ break;
|
||||
+#endif /* ?UNIX */
|
||||
case 'l': /* longer form of "ls -l" type listing */
|
||||
if (negative)
|
||||
uO.lflag = -2, negative = 0;
|
||||
@@ -521,6 +554,35 @@
|
||||
G.M_flag = TRUE;
|
||||
break;
|
||||
#endif
|
||||
+#ifdef UNIX
|
||||
+ case ('O'):
|
||||
+ if (negative) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: encodings can't be negated"));
|
||||
+ return(PK_PARAM);
|
||||
+ } else {
|
||||
+ if(*s) { /* Handle the -Ocharset case */
|
||||
+ /* Assume that charsets can't start with a dash to spot arguments misuse */
|
||||
+ if(*s == '-') {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: a valid character encoding should follow the -I argument"));
|
||||
+ return(PK_PARAM);
|
||||
+ }
|
||||
+ strncpy(OEM_CP, s, sizeof(OEM_CP));
|
||||
+ } else { /* -O charset */
|
||||
+ ++argv;
|
||||
+ if(!(--argc > 0 && *argv != NULL && **argv != '-')) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ "error: a valid character encoding should follow the -O argument"));
|
||||
+ return(PK_PARAM);
|
||||
+ }
|
||||
+ s = *argv;
|
||||
+ strncpy(OEM_CP, s, sizeof(OEM_CP));
|
||||
+ }
|
||||
+ while(*(++s)); /* No params straight after charset name */
|
||||
+ }
|
||||
+ break;
|
||||
+#endif /* ?UNIX */
|
||||
case 's': /* default: shorter "ls -l" type listing */
|
||||
if (negative)
|
||||
uO.lflag = -2, negative = 0;
|
||||
@@ -0,0 +1,12 @@
|
||||
diff -up unzip60/zipinfo.c.attribs-overflow unzip60/zipinfo.c
|
||||
--- unzip60/zipinfo.c.attribs-overflow 2009-11-30 09:55:39.000000000 +0100
|
||||
+++ unzip60/zipinfo.c 2009-11-30 09:56:42.844263244 +0100
|
||||
@@ -1881,7 +1881,7 @@ static int zi_short(__G) /* return PK-
|
||||
#endif
|
||||
int k, error, error_in_archive=PK_COOL;
|
||||
unsigned hostnum, hostver, methid, methnum, xattr;
|
||||
- char *p, workspace[12], attribs[16];
|
||||
+ char *p, workspace[12], attribs[17];
|
||||
char methbuf[5];
|
||||
static ZCONST char dtype[5]="NXFS"; /* normal, maximum, fast, superfast */
|
||||
static ZCONST char Far os[NUM_HOSTS+1][4] = {
|
||||
@@ -0,0 +1,176 @@
|
||||
diff -up unzip60/extract.c.close unzip60/extract.c
|
||||
--- unzip60/extract.c.close 2009-03-14 02:32:52.000000000 +0100
|
||||
+++ unzip60/extract.c 2009-11-19 08:17:23.481263496 +0100
|
||||
@@ -1924,24 +1924,21 @@ static int extract_or_test_member(__G)
|
||||
|
||||
#ifdef VMS /* VMS: required even for stdout! (final flush) */
|
||||
if (!uO.tflag) /* don't close NULL file */
|
||||
- close_outfile(__G);
|
||||
+ error = close_outfile(__G);
|
||||
#else
|
||||
#ifdef DLL
|
||||
if (!uO.tflag && (!uO.cflag || G.redirect_data)) {
|
||||
if (G.redirect_data)
|
||||
FINISH_REDIRECT();
|
||||
else
|
||||
- close_outfile(__G);
|
||||
+ error = close_outfile(__G);
|
||||
}
|
||||
#else
|
||||
if (!uO.tflag && !uO.cflag) /* don't close NULL file or stdout */
|
||||
- close_outfile(__G);
|
||||
+ error = close_outfile(__G);
|
||||
#endif
|
||||
#endif /* VMS */
|
||||
|
||||
- /* GRR: CONVERT close_outfile() TO NON-VOID: CHECK FOR ERRORS! */
|
||||
-
|
||||
-
|
||||
if (G.disk_full) { /* set by flush() */
|
||||
if (G.disk_full > 1) {
|
||||
#if (defined(DELETE_IF_FULL) && defined(HAVE_UNLINK))
|
||||
diff -up unzip60/unix/unix.c.close unzip60/unix/unix.c
|
||||
--- unzip60/unix/unix.c.close 2009-01-24 00:31:26.000000000 +0100
|
||||
+++ unzip60/unix/unix.c 2009-11-19 08:33:25.568389171 +0100
|
||||
@@ -1096,10 +1096,41 @@ static int get_extattribs(__G__ pzt, z_u
|
||||
#ifndef MTS
|
||||
|
||||
/****************************/
|
||||
+/* Function CloseError() */
|
||||
+/***************************/
|
||||
+
|
||||
+int CloseError(__G)
|
||||
+ __GDEF
|
||||
+{
|
||||
+ int errval = PK_OK;
|
||||
+
|
||||
+ if (fclose(G.outfile) < 0) {
|
||||
+ switch (errno) {
|
||||
+ case ENOSPC:
|
||||
+ /* Do we need this on fileio.c? */
|
||||
+ Info(slide, 0x4a1, ((char *)slide, "%s: write error (disk full?). Continue? (y/n/^C) ",
|
||||
+ FnFilter1(G.filename)));
|
||||
+ fgets(G.answerbuf, 9, stdin);
|
||||
+ if (*G.answerbuf == 'y') /* stop writing to this file */
|
||||
+ G.disk_full = 1; /* pass to next */
|
||||
+ else
|
||||
+ G.disk_full = 2; /* no: exit program */
|
||||
+
|
||||
+ errval = PK_DISK;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ errval = PK_WARN;
|
||||
+ }
|
||||
+ }
|
||||
+ return errval;
|
||||
+} /* End of CloseError() */
|
||||
+
|
||||
+/****************************/
|
||||
/* Function close_outfile() */
|
||||
/****************************/
|
||||
|
||||
-void close_outfile(__G) /* GRR: change to return PK-style warning level */
|
||||
+int close_outfile(__G)
|
||||
__GDEF
|
||||
{
|
||||
union {
|
||||
@@ -1108,6 +1139,7 @@ void close_outfile(__G) /* GRR: chang
|
||||
} zt;
|
||||
ulg z_uidgid[2];
|
||||
int have_uidgid_flg;
|
||||
+ int errval = PK_OK;
|
||||
|
||||
have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid);
|
||||
|
||||
@@ -1141,16 +1173,16 @@ void close_outfile(__G) /* GRR: chang
|
||||
Info(slide, 0x201, ((char *)slide,
|
||||
"warning: symbolic link (%s) failed: mem alloc overflow\n",
|
||||
FnFilter1(G.filename)));
|
||||
- fclose(G.outfile);
|
||||
- return;
|
||||
+ errval = CloseError(G.outfile, G.filename);
|
||||
+ return errval ? errval : PK_WARN;
|
||||
}
|
||||
|
||||
if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) {
|
||||
Info(slide, 0x201, ((char *)slide,
|
||||
"warning: symbolic link (%s) failed: no mem\n",
|
||||
FnFilter1(G.filename)));
|
||||
- fclose(G.outfile);
|
||||
- return;
|
||||
+ errval = CloseError(G.outfile, G.filename);
|
||||
+ return errval ? errval : PK_WARN;
|
||||
}
|
||||
slnk_entry->next = NULL;
|
||||
slnk_entry->targetlen = ucsize;
|
||||
@@ -1174,10 +1206,10 @@ void close_outfile(__G) /* GRR: chang
|
||||
"warning: symbolic link (%s) failed\n",
|
||||
FnFilter1(G.filename)));
|
||||
free(slnk_entry);
|
||||
- fclose(G.outfile);
|
||||
- return;
|
||||
+ errval = CloseError(G.outfile, G.filename);
|
||||
+ return errval ? errval : PK_WARN;
|
||||
}
|
||||
- fclose(G.outfile); /* close "link" file for good... */
|
||||
+ errval = CloseError(G.outfile, G.filename); /* close "link" file for good... */
|
||||
slnk_entry->target[ucsize] = '\0';
|
||||
if (QCOND2)
|
||||
Info(slide, 0, ((char *)slide, "-> %s ",
|
||||
@@ -1188,7 +1220,7 @@ void close_outfile(__G) /* GRR: chang
|
||||
else
|
||||
G.slink_head = slnk_entry;
|
||||
G.slink_last = slnk_entry;
|
||||
- return;
|
||||
+ return errval;
|
||||
}
|
||||
#endif /* SYMLINKS */
|
||||
|
||||
@@ -1201,7 +1233,7 @@ void close_outfile(__G) /* GRR: chang
|
||||
#endif
|
||||
|
||||
#if (defined(NO_FCHOWN))
|
||||
- fclose(G.outfile);
|
||||
+ errval = CloseError(G.outfile, G.filename);
|
||||
#endif
|
||||
|
||||
/* if -X option was specified and we have UID/GID info, restore it */
|
||||
@@ -1227,7 +1259,7 @@ void close_outfile(__G) /* GRR: chang
|
||||
}
|
||||
|
||||
#if (!defined(NO_FCHOWN) && defined(NO_FCHMOD))
|
||||
- fclose(G.outfile);
|
||||
+ errval = CloseError(G.outfile, G.filename);
|
||||
#endif
|
||||
|
||||
#if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD))
|
||||
@@ -1239,7 +1271,7 @@ void close_outfile(__G) /* GRR: chang
|
||||
if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr)))
|
||||
perror("fchmod (file attributes) error");
|
||||
|
||||
- fclose(G.outfile);
|
||||
+ errval = CloseError(G.outfile, G.filename);
|
||||
#endif /* !NO_FCHOWN && !NO_FCHMOD */
|
||||
|
||||
/* skip restoring time stamps on user's request */
|
||||
@@ -1267,6 +1299,7 @@ void close_outfile(__G) /* GRR: chang
|
||||
#endif
|
||||
#endif /* NO_FCHOWN || NO_FCHMOD */
|
||||
|
||||
+ return errval;
|
||||
} /* end function close_outfile() */
|
||||
|
||||
#endif /* !MTS */
|
||||
diff -up unzip60/unzpriv.h.close unzip60/unzpriv.h
|
||||
--- unzip60/unzpriv.h.close 2009-04-20 01:59:26.000000000 +0200
|
||||
+++ unzip60/unzpriv.h 2009-11-19 08:19:08.610388618 +0100
|
||||
@@ -2604,7 +2604,7 @@ char *GetLoadPath OF((__GPRO));
|
||||
int SetFileSize OF((FILE *file, zusz_t filesize)); /* local */
|
||||
#endif
|
||||
#ifndef MTS /* macro in MTS */
|
||||
- void close_outfile OF((__GPRO)); /* local */
|
||||
+ int close_outfile OF((__GPRO)); /* local */
|
||||
#endif
|
||||
#ifdef SET_SYMLINK_ATTRIBS
|
||||
int set_symlnk_attribs OF((__GPRO__ slinkentry *slnk_entry)); /* local */
|
||||
@@ -0,0 +1,79 @@
|
||||
diff --git a/extract.c b/extract.c
|
||||
index 9ef80b3..c741b5f 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
- Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
|
||||
+ Copyright (c) 1990-2014 Info-ZIP. All rights reserved.
|
||||
|
||||
See the accompanying file LICENSE, version 2009-Jan-02 or later
|
||||
(the contents of which are also included in unzip.h) for terms of use.
|
||||
@@ -298,6 +298,8 @@ char ZCONST Far TruncNTSD[] =
|
||||
#ifndef SFX
|
||||
static ZCONST char Far InconsistEFlength[] = "bad extra-field entry:\n \
|
||||
EF block length (%u bytes) exceeds remaining EF data (%u bytes)\n";
|
||||
+ static ZCONST char Far TooSmallEBlength[] = "bad extra-field entry:\n \
|
||||
+ EF block length (%u bytes) invalid (< %d)\n";
|
||||
static ZCONST char Far InvalidComprDataEAs[] =
|
||||
" invalid compressed data for EAs\n";
|
||||
# if (defined(WIN32) && defined(NTSD_EAS))
|
||||
@@ -2020,7 +2022,8 @@ static int TestExtraField(__G__ ef, ef_len)
|
||||
ebID = makeword(ef);
|
||||
ebLen = (unsigned)makeword(ef+EB_LEN);
|
||||
|
||||
- if (ebLen > (ef_len - EB_HEADSIZE)) {
|
||||
+ if (ebLen > (ef_len - EB_HEADSIZE))
|
||||
+ {
|
||||
/* Discovered some extra field inconsistency! */
|
||||
if (uO.qflag)
|
||||
Info(slide, 1, ((char *)slide, "%-22s ",
|
||||
@@ -2155,11 +2158,29 @@ static int TestExtraField(__G__ ef, ef_len)
|
||||
}
|
||||
break;
|
||||
case EF_PKVMS:
|
||||
- if (makelong(ef+EB_HEADSIZE) !=
|
||||
- crc32(CRCVAL_INITIAL, ef+(EB_HEADSIZE+4),
|
||||
- (extent)(ebLen-4)))
|
||||
- Info(slide, 1, ((char *)slide,
|
||||
- LoadFarString(BadCRC_EAs)));
|
||||
+ /* 2015-01-30 SMS. Added sufficient-bytes test/message
|
||||
+ * here. (Removed defective ebLen test above.)
|
||||
+ *
|
||||
+ * If sufficient bytes (EB_PKVMS_MINLEN) are available,
|
||||
+ * then compare the stored CRC value with the calculated
|
||||
+ * CRC for the remainder of the data (and complain about
|
||||
+ * a mismatch).
|
||||
+ */
|
||||
+ if (ebLen < EB_PKVMS_MINLEN)
|
||||
+ {
|
||||
+ /* Insufficient bytes available. */
|
||||
+ Info( slide, 1,
|
||||
+ ((char *)slide, LoadFarString( TooSmallEBlength),
|
||||
+ ebLen, EB_PKVMS_MINLEN));
|
||||
+ }
|
||||
+ else if (makelong(ef+ EB_HEADSIZE) !=
|
||||
+ crc32(CRCVAL_INITIAL,
|
||||
+ (ef+ EB_HEADSIZE+ EB_PKVMS_MINLEN),
|
||||
+ (extent)(ebLen- EB_PKVMS_MINLEN)))
|
||||
+ {
|
||||
+ Info(slide, 1, ((char *)slide,
|
||||
+ LoadFarString(BadCRC_EAs)));
|
||||
+ }
|
||||
break;
|
||||
case EF_PKW32:
|
||||
case EF_PKUNIX:
|
||||
diff --git a/unzpriv.h b/unzpriv.h
|
||||
index 005cee0..5c83a6e 100644
|
||||
--- a/unzpriv.h
|
||||
+++ b/unzpriv.h
|
||||
@@ -1806,6 +1806,8 @@
|
||||
#define EB_NTSD_VERSION 4 /* offset of NTSD version byte */
|
||||
#define EB_NTSD_MAX_VER (0) /* maximum version # we know how to handle */
|
||||
|
||||
+#define EB_PKVMS_MINLEN 4 /* minimum data length of PKVMS extra block */
|
||||
+
|
||||
#define EB_ASI_CRC32 0 /* offset of ASI Unix field's crc32 checksum */
|
||||
#define EB_ASI_MODE 4 /* offset of ASI Unix permission mode field */
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
diff --git a/extract.c b/extract.c
|
||||
index c741b5f..e4a4c7b 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -2240,10 +2240,17 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
|
||||
if (compr_offset < 4) /* field is not compressed: */
|
||||
return PK_OK; /* do nothing and signal OK */
|
||||
|
||||
+ /* Return no/bad-data error status if any problem is found:
|
||||
+ * 1. eb_size is too small to hold the uncompressed size
|
||||
+ * (eb_ucsize). (Else extract eb_ucsize.)
|
||||
+ * 2. eb_ucsize is zero (invalid). 2014-12-04 SMS.
|
||||
+ * 3. eb_ucsize is positive, but eb_size is too small to hold
|
||||
+ * the compressed data header.
|
||||
+ */
|
||||
if ((eb_size < (EB_UCSIZE_P + 4)) ||
|
||||
- ((eb_ucsize = makelong(eb+(EB_HEADSIZE+EB_UCSIZE_P))) > 0L &&
|
||||
- eb_size <= (compr_offset + EB_CMPRHEADLEN)))
|
||||
- return IZ_EF_TRUNC; /* no compressed data! */
|
||||
+ ((eb_ucsize = makelong( eb+ (EB_HEADSIZE+ EB_UCSIZE_P))) == 0L) ||
|
||||
+ ((eb_ucsize > 0L) && (eb_size <= (compr_offset + EB_CMPRHEADLEN))))
|
||||
+ return IZ_EF_TRUNC; /* no/bad compressed data! */
|
||||
|
||||
method = makeword(eb + (EB_HEADSIZE + compr_offset));
|
||||
if ((method == STORED) && (eb_size != compr_offset + EB_CMPRHEADLEN + eb_ucsize))
|
||||
@@ -0,0 +1,138 @@
|
||||
diff --git a/fileio.c b/fileio.c
|
||||
index 03fc4be..2a61a30 100644
|
||||
--- a/fileio.c
|
||||
+++ b/fileio.c
|
||||
@@ -176,6 +176,8 @@ static ZCONST char Far FilenameTooLongTrunc[] =
|
||||
#endif
|
||||
static ZCONST char Far ExtraFieldTooLong[] =
|
||||
"warning: extra field too long (%d). Ignoring...\n";
|
||||
+static ZCONST char Far ExtraFieldCorrupt[] =
|
||||
+ "warning: extra field (type: 0x%04x) corrupt. Continuing...\n";
|
||||
|
||||
#ifdef WINDLL
|
||||
static ZCONST char Far DiskFullQuery[] =
|
||||
@@ -2300,7 +2302,13 @@ int do_string(__G__ length, option) /* return PK-type error code */
|
||||
length = length2;
|
||||
}
|
||||
/* Looks like here is where extra fields are read */
|
||||
- getZip64Data(__G__ G.extra_field, length);
|
||||
+ if (getZip64Data(__G__ G.extra_field, length) != PK_COOL)
|
||||
+ {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ LoadFarString( ExtraFieldCorrupt), EF_PKSZ64));
|
||||
+ error = PK_WARN;
|
||||
+ }
|
||||
+
|
||||
#ifdef UNICODE_SUPPORT
|
||||
G.unipath_filename = NULL;
|
||||
if (G.UzO.U_flag < 2) {
|
||||
diff --git a/process.c b/process.c
|
||||
index be6e006..0d57ab4 100644
|
||||
--- a/process.c
|
||||
+++ b/process.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
- Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
|
||||
+ Copyright (c) 1990-2014 Info-ZIP. All rights reserved.
|
||||
|
||||
See the accompanying file LICENSE, version 2009-Jan-02 or later
|
||||
(the contents of which are also included in unzip.h) for terms of use.
|
||||
@@ -1894,48 +1894,83 @@ int getZip64Data(__G__ ef_buf, ef_len)
|
||||
and a 4-byte version of disk start number.
|
||||
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.
|
||||
+ 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
|
||||
+ on our variable sizes.) Error handling is crude, but we should now
|
||||
+ stay within the buffer.
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
+#define Z64FLGS 0xffff
|
||||
+#define Z64FLGL 0xffffffff
|
||||
+
|
||||
if (ef_len == 0 || ef_buf == NULL)
|
||||
return PK_COOL;
|
||||
|
||||
Trace((stderr,"\ngetZip64Data: scanning extra field of length %u\n",
|
||||
ef_len));
|
||||
|
||||
- while (ef_len >= EB_HEADSIZE) {
|
||||
+ while (ef_len >= EB_HEADSIZE)
|
||||
+ {
|
||||
eb_id = makeword(EB_ID + ef_buf);
|
||||
eb_len = makeword(EB_LEN + ef_buf);
|
||||
|
||||
- if (eb_len > (ef_len - EB_HEADSIZE)) {
|
||||
- /* discovered some extra field inconsistency! */
|
||||
+ if (eb_len > (ef_len - EB_HEADSIZE))
|
||||
+ {
|
||||
+ /* Extra block length exceeds remaining extra field length. */
|
||||
Trace((stderr,
|
||||
"getZip64Data: block length %u > rest ef_size %u\n", eb_len,
|
||||
ef_len - EB_HEADSIZE));
|
||||
break;
|
||||
}
|
||||
- if (eb_id == EF_PKSZ64) {
|
||||
|
||||
+ if (eb_id == EF_PKSZ64)
|
||||
+ {
|
||||
int offset = EB_HEADSIZE;
|
||||
|
||||
- if (G.crec.ucsize == 0xffffffff || G.lrec.ucsize == 0xffffffff){
|
||||
- G.lrec.ucsize = G.crec.ucsize = makeint64(offset + ef_buf);
|
||||
- offset += sizeof(G.crec.ucsize);
|
||||
+ if ((G.crec.ucsize == Z64FLGL) || (G.lrec.ucsize == Z64FLGL))
|
||||
+ {
|
||||
+ if (offset+ 8 > ef_len)
|
||||
+ return PK_ERR;
|
||||
+
|
||||
+ G.crec.ucsize = G.lrec.ucsize = makeint64(offset + ef_buf);
|
||||
+ offset += 8;
|
||||
}
|
||||
- if (G.crec.csize == 0xffffffff || G.lrec.csize == 0xffffffff){
|
||||
- G.csize = G.lrec.csize = G.crec.csize = makeint64(offset + ef_buf);
|
||||
- offset += sizeof(G.crec.csize);
|
||||
+
|
||||
+ if ((G.crec.csize == Z64FLGL) || (G.lrec.csize == Z64FLGL))
|
||||
+ {
|
||||
+ if (offset+ 8 > ef_len)
|
||||
+ return PK_ERR;
|
||||
+
|
||||
+ G.csize = G.crec.csize = G.lrec.csize = makeint64(offset + ef_buf);
|
||||
+ offset += 8;
|
||||
}
|
||||
- if (G.crec.relative_offset_local_header == 0xffffffff){
|
||||
+
|
||||
+ if (G.crec.relative_offset_local_header == Z64FLGL)
|
||||
+ {
|
||||
+ if (offset+ 8 > ef_len)
|
||||
+ return PK_ERR;
|
||||
+
|
||||
G.crec.relative_offset_local_header = makeint64(offset + ef_buf);
|
||||
- offset += sizeof(G.crec.relative_offset_local_header);
|
||||
+ offset += 8;
|
||||
}
|
||||
- if (G.crec.disk_number_start == 0xffff){
|
||||
+
|
||||
+ if (G.crec.disk_number_start == Z64FLGS)
|
||||
+ {
|
||||
+ if (offset+ 4 > ef_len)
|
||||
+ return PK_ERR;
|
||||
+
|
||||
G.crec.disk_number_start = (zuvl_t)makelong(offset + ef_buf);
|
||||
- offset += sizeof(G.crec.disk_number_start);
|
||||
+ offset += 4;
|
||||
}
|
||||
+#if 0
|
||||
+ break; /* Expect only one EF_PKSZ64 block. */
|
||||
+#endif /* 0 */
|
||||
}
|
||||
|
||||
- /* Skip this extra field block */
|
||||
+ /* Skip this extra field block. */
|
||||
ef_buf += (eb_len + EB_HEADSIZE);
|
||||
ef_len -= (eb_len + EB_HEADSIZE);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
--- a/fileio.c 2014-12-05 05:06:05 -0600
|
||||
+++ b/fileio.c 2017-11-14 01:06:28 -0600
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
- Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
|
||||
+ Copyright (c) 1990-2017 Info-ZIP. All rights reserved.
|
||||
|
||||
See the accompanying file LICENSE, version 2009-Jan-02 or later
|
||||
(the contents of which are also included in unzip.h) for terms of use.
|
||||
@@ -1582,6 +1582,8 @@
|
||||
int r = IZ_PW_ENTERED;
|
||||
char *m;
|
||||
char *prompt;
|
||||
+ char *ep;
|
||||
+ char *zp;
|
||||
|
||||
#ifndef REENTRANT
|
||||
/* tell picky compilers to shut up about "unused variable" warnings */
|
||||
@@ -1590,9 +1592,12 @@
|
||||
|
||||
if (*rcnt == 0) { /* First call for current entry */
|
||||
*rcnt = 2;
|
||||
- if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) {
|
||||
- sprintf(prompt, LoadFarString(PasswPrompt),
|
||||
- FnFilter1(zfn), FnFilter2(efn));
|
||||
+ zp = FnFilter1( zfn);
|
||||
+ ep = FnFilter2( efn);
|
||||
+ prompt = (char *)malloc( /* Slightly too long (2* "%s"). */
|
||||
+ sizeof( PasswPrompt)+ strlen( zp)+ strlen( ep));
|
||||
+ if (prompt != (char *)NULL) {
|
||||
+ sprintf(prompt, LoadFarString(PasswPrompt), zp, ep);
|
||||
m = prompt;
|
||||
} else
|
||||
m = (char *)LoadFarString(PasswPrompt2);
|
||||
@@ -0,0 +1,35 @@
|
||||
--- unzip60/list.c
|
||||
+++ unzip60/list.c
|
||||
@@ -97,7 +97,7 @@ int list_files(__G) /* return PK-type
|
||||
{
|
||||
int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
|
||||
#ifndef WINDLL
|
||||
- char sgn, cfactorstr[13];
|
||||
+ char sgn, cfactorstr[1+10+1+1]; /* <sgn><int>%NUL */
|
||||
int longhdr=(uO.vflag>1);
|
||||
#endif
|
||||
int date_format;
|
||||
@@ -389,9 +389,9 @@ int list_files(__G) /* return PK-type
|
||||
}
|
||||
#else /* !WINDLL */
|
||||
if (cfactor == 100)
|
||||
- sprintf(cfactorstr, LoadFarString(CompFactor100));
|
||||
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100));
|
||||
else
|
||||
- sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
|
||||
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor);
|
||||
if (longhdr)
|
||||
Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats),
|
||||
FmZofft(G.crec.ucsize, "8", "u"), methbuf,
|
||||
@@ -471,9 +471,9 @@ int list_files(__G) /* return PK-type
|
||||
|
||||
#else /* !WINDLL */
|
||||
if (cfactor == 100)
|
||||
- sprintf(cfactorstr, LoadFarString(CompFactor100));
|
||||
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactor100));
|
||||
else
|
||||
- sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
|
||||
+ snprintf(cfactorstr, sizeof(cfactorstr), LoadFarString(CompFactorStr), sgn, cfactor);
|
||||
if (longhdr) {
|
||||
Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer),
|
||||
FmZofft(tot_ucsize, "8", "u"), FmZofft(tot_csize, "8", "u"),
|
||||
@@ -0,0 +1,10 @@
|
||||
diff -up unzip60/crc_i386.S.exec-shield unzip60/crc_i386.S
|
||||
--- unzip60/crc_i386.S.exec-shield 2007-01-07 06:02:58.000000000 +0100
|
||||
+++ unzip60/crc_i386.S 2009-11-18 11:16:39.630389312 +0100
|
||||
@@ -302,3 +302,6 @@ _crc32: /* ulg c
|
||||
#endif /* i386 || _i386 || _I386 || __i386 */
|
||||
|
||||
#endif /* !USE_ZLIB && !CRC_TABLE_ONLY */
|
||||
+
|
||||
+.section .note.GNU-stack, "", @progbits
|
||||
+.previous
|
||||
@@ -0,0 +1,90 @@
|
||||
diff --git a/extract.c b/extract.c
|
||||
index eeb2f57..a0a4929 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -472,8 +472,8 @@ int extract_or_test_files(__G) /* return PK-type error code */
|
||||
*/
|
||||
Info(slide, 0x401, ((char *)slide,
|
||||
LoadFarString(CentSigMsg), j + blknum*DIR_BLKSIZ + 1));
|
||||
- Info(slide, 0x401, ((char *)slide,
|
||||
- LoadFarString(ReportMsg)));
|
||||
+ Info(slide, 0x401,
|
||||
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
|
||||
error_in_archive = PK_BADERR;
|
||||
}
|
||||
reached_end = TRUE; /* ...so no more left to do */
|
||||
@@ -752,8 +752,8 @@ int extract_or_test_files(__G) /* return PK-type error code */
|
||||
|
||||
#ifndef SFX
|
||||
if (no_endsig_found) { /* just to make sure */
|
||||
- Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
|
||||
- Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg)));
|
||||
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg)));
|
||||
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(ReportMsg)));
|
||||
if (!error_in_archive) /* don't overwrite stronger error */
|
||||
error_in_archive = PK_WARN;
|
||||
}
|
||||
diff --git a/list.c b/list.c
|
||||
index 15e0011..f7359c3 100644
|
||||
--- a/list.c
|
||||
+++ b/list.c
|
||||
@@ -181,7 +181,7 @@ int list_files(__G) /* return PK-type error code */
|
||||
Info(slide, 0x401,
|
||||
((char *)slide, LoadFarString(CentSigMsg), j));
|
||||
Info(slide, 0x401,
|
||||
- ((char *)slide, LoadFarString(ReportMsg)));
|
||||
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
|
||||
return PK_BADERR; /* sig not found */
|
||||
}
|
||||
}
|
||||
@@ -507,7 +507,8 @@ int list_files(__G) /* return PK-type error code */
|
||||
&& (!G.ecrec.is_zip64_archive)
|
||||
&& (memcmp(G.sig, end_central_sig, 4) != 0)
|
||||
) { /* just to make sure again */
|
||||
- Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
|
||||
+ Info(slide, 0x401,
|
||||
+ ((char *)slide,"%s", LoadFarString(EndSigMsg)));
|
||||
error_in_archive = PK_WARN; /* didn't find sig */
|
||||
}
|
||||
|
||||
@@ -591,7 +592,7 @@ int get_time_stamp(__G__ last_modtime, nmember) /* return PK-type error code */
|
||||
Info(slide, 0x401,
|
||||
((char *)slide, LoadFarString(CentSigMsg), j));
|
||||
Info(slide, 0x401,
|
||||
- ((char *)slide, LoadFarString(ReportMsg)));
|
||||
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
|
||||
return PK_BADERR; /* sig not found */
|
||||
}
|
||||
}
|
||||
@@ -674,7 +675,7 @@ int get_time_stamp(__G__ last_modtime, nmember) /* return PK-type error code */
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
if (memcmp(G.sig, end_central_sig, 4)) { /* just to make sure again */
|
||||
- Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
|
||||
+ Info(slide, 0x401, ((char *)slide,"%s", LoadFarString(EndSigMsg)));
|
||||
error_in_archive = PK_WARN;
|
||||
}
|
||||
if (*nmember == 0L && error_in_archive <= PK_WARN)
|
||||
diff --git a/zipinfo.c b/zipinfo.c
|
||||
index 6e22cc8..ac5c61b 100644
|
||||
--- a/zipinfo.c
|
||||
+++ b/zipinfo.c
|
||||
@@ -771,7 +771,7 @@ int zipinfo(__G) /* return PK-type error code */
|
||||
Info(slide, 0x401,
|
||||
((char *)slide, LoadFarString(CentSigMsg), j));
|
||||
Info(slide, 0x401,
|
||||
- ((char *)slide, LoadFarString(ReportMsg)));
|
||||
+ ((char *)slide,"%s", LoadFarString(ReportMsg)));
|
||||
error_in_archive = PK_BADERR; /* sig not found */
|
||||
break;
|
||||
}
|
||||
@@ -960,7 +960,8 @@ int zipinfo(__G) /* return PK-type error code */
|
||||
&& (!G.ecrec.is_zip64_archive)
|
||||
&& (memcmp(G.sig, end_central_sig, 4) != 0)
|
||||
) { /* just to make sure again */
|
||||
- Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
|
||||
+ Info(slide, 0x401,
|
||||
+ ((char *)slide,"%s", LoadFarString(EndSigMsg)));
|
||||
error_in_archive = PK_WARN; /* didn't find sig */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
From bdd4a0cecd745cb4825e4508b5bdf2579731086a Mon Sep 17 00:00:00 2001
|
||||
From: Petr Stodulka <[email protected]>
|
||||
Date: Mon, 14 Sep 2015 18:23:17 +0200
|
||||
Subject: [PATCH 1/3] upstream fix for heap overflow
|
||||
|
||||
https://bugzilla.redhat.com/attachment.cgi?id=1073002
|
||||
---
|
||||
crypt.c | 12 +++++++++++-
|
||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/crypt.c b/crypt.c
|
||||
index 784e411..a8975f2 100644
|
||||
--- a/crypt.c
|
||||
+++ b/crypt.c
|
||||
@@ -465,7 +465,17 @@ int decrypt(__G__ passwrd)
|
||||
GLOBAL(pInfo->encrypted) = FALSE;
|
||||
defer_leftover_input(__G);
|
||||
for (n = 0; n < RAND_HEAD_LEN; n++) {
|
||||
- b = NEXTBYTE;
|
||||
+ /* 2012-11-23 SMS. (OUSPG report.)
|
||||
+ * Quit early if compressed size < HEAD_LEN. The resulting
|
||||
+ * error message ("unable to get password") could be improved,
|
||||
+ * but it's better than trying to read nonexistent data, and
|
||||
+ * then continuing with a negative G.csize. (See
|
||||
+ * fileio.c:readbyte()).
|
||||
+ */
|
||||
+ if ((b = NEXTBYTE) == (ush)EOF)
|
||||
+ {
|
||||
+ return PK_ERR;
|
||||
+ }
|
||||
h[n] = (uch)b;
|
||||
Trace((stdout, " (%02x)", h[n]));
|
||||
}
|
||||
--
|
||||
2.4.6
|
||||
|
||||
|
||||
From 4b48844661ff9569f2ecf582a387d46a5775b5d8 Mon Sep 17 00:00:00 2001
|
||||
From: Kamil Dudka <[email protected]>
|
||||
Date: Mon, 14 Sep 2015 18:24:56 +0200
|
||||
Subject: [PATCH 2/3] fix infinite loop when extracting empty bzip2 data
|
||||
|
||||
Bug: https://sourceforge.net/p/infozip/patches/23/
|
||||
---
|
||||
extract.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/extract.c b/extract.c
|
||||
index 7134bfe..29db027 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -2733,6 +2733,12 @@ __GDEF
|
||||
int repeated_buf_err;
|
||||
bz_stream bstrm;
|
||||
|
||||
+ if (G.incnt <= 0 && G.csize <= 0L) {
|
||||
+ /* avoid an infinite loop */
|
||||
+ Trace((stderr, "UZbunzip2() got empty input\n"));
|
||||
+ return 2;
|
||||
+ }
|
||||
+
|
||||
#if (defined(DLL) && !defined(NO_SLIDE_REDIR))
|
||||
if (G.redirect_slide)
|
||||
wsize = G.redirect_size, redirSlide = G.redirect_buffer;
|
||||
--
|
||||
2.4.6
|
||||
|
||||
|
||||
From bd150334fb4084f5555a6be26b015a0671cb5b74 Mon Sep 17 00:00:00 2001
|
||||
From: Kamil Dudka <[email protected]>
|
||||
Date: Tue, 22 Sep 2015 18:52:23 +0200
|
||||
Subject: [PATCH 3/3] extract: prevent unsigned overflow on invalid input
|
||||
|
||||
Suggested-by: Stefan Cornelius
|
||||
---
|
||||
extract.c | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/extract.c b/extract.c
|
||||
index 29db027..b9ae667 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -1257,8 +1257,17 @@ static int extract_or_test_entrylist(__G__ numchunk,
|
||||
if (G.lrec.compression_method == STORED) {
|
||||
zusz_t csiz_decrypted = G.lrec.csize;
|
||||
|
||||
- if (G.pInfo->encrypted)
|
||||
+ if (G.pInfo->encrypted) {
|
||||
+ if (csiz_decrypted < 12) {
|
||||
+ /* handle the error now to prevent unsigned overflow */
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ LoadFarStringSmall(ErrUnzipNoFile),
|
||||
+ LoadFarString(InvalidComprData),
|
||||
+ LoadFarStringSmall2(Inflate)));
|
||||
+ return PK_ERR;
|
||||
+ }
|
||||
csiz_decrypted -= 12;
|
||||
+ }
|
||||
if (G.lrec.ucsize != csiz_decrypted) {
|
||||
Info(slide, 0x401, ((char *)slide,
|
||||
LoadFarStringSmall2(WrnStorUCSizCSizDiff),
|
||||
--
|
||||
2.5.2
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
diff --git a/list.c b/list.c
|
||||
index f7359c3..4c3d703 100644
|
||||
--- a/list.c
|
||||
+++ b/list.c
|
||||
@@ -97,7 +97,7 @@ int list_files(__G) /* return PK-type error code */
|
||||
{
|
||||
int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
|
||||
#ifndef WINDLL
|
||||
- char sgn, cfactorstr[10];
|
||||
+ char sgn, cfactorstr[13];
|
||||
int longhdr=(uO.vflag>1);
|
||||
#endif
|
||||
int date_format;
|
||||
@@ -339,7 +339,19 @@ int list_files(__G) /* return PK-type error code */
|
||||
G.crec.compression_method == ENHDEFLATED) {
|
||||
methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3];
|
||||
} else if (methnum >= NUM_METHODS) {
|
||||
- sprintf(&methbuf[4], "%03u", G.crec.compression_method);
|
||||
+ /* 2013-02-26 SMS.
|
||||
+ * http://sourceforge.net/tracker/?func=detail
|
||||
+ * &aid=2861648&group_id=118012&atid=679786
|
||||
+ * Unexpectedly large compression methods overflow
|
||||
+ * &methbuf[]. Use the old, three-digit decimal format
|
||||
+ * for values which fit. Otherwise, sacrifice the
|
||||
+ * colon, and use four-digit hexadecimal.
|
||||
+ */
|
||||
+ if (G.crec.compression_method <= 999) {
|
||||
+ sprintf( &methbuf[ 4], "%03u", G.crec.compression_method);
|
||||
+ } else {
|
||||
+ sprintf( &methbuf[ 3], "%04X", G.crec.compression_method);
|
||||
+ }
|
||||
}
|
||||
|
||||
#if 0 /* GRR/Euro: add this? */
|
||||
@@ -0,0 +1,25 @@
|
||||
diff --git a/extract.c b/extract.c
|
||||
index a0a4929..9ef80b3 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -2214,6 +2214,7 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
|
||||
ulg eb_ucsize;
|
||||
uch *eb_ucptr;
|
||||
int r;
|
||||
+ ush method;
|
||||
|
||||
if (compr_offset < 4) /* field is not compressed: */
|
||||
return PK_OK; /* do nothing and signal OK */
|
||||
@@ -2223,6 +2224,12 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offset, test_uc_ebdata)
|
||||
eb_size <= (compr_offset + EB_CMPRHEADLEN)))
|
||||
return IZ_EF_TRUNC; /* no compressed data! */
|
||||
|
||||
+ method = makeword(eb + (EB_HEADSIZE + compr_offset));
|
||||
+ if ((method == STORED) && (eb_size != compr_offset + EB_CMPRHEADLEN + eb_ucsize))
|
||||
+ return PK_ERR; /* compressed & uncompressed
|
||||
+ * should match in STORED
|
||||
+ * method */
|
||||
+
|
||||
if (
|
||||
#ifdef INT_16BIT
|
||||
(((ulg)(extent)eb_ucsize) != eb_ucsize) ||
|
||||
@@ -0,0 +1,17 @@
|
||||
diff --git a/process.c b/process.c
|
||||
index 1e9a1e1..905732b 100644
|
||||
--- a/process.c
|
||||
+++ b/process.c
|
||||
@@ -1751,6 +1751,12 @@ int process_cdir_file_hdr(__G) /* return PK-type error code */
|
||||
= (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11);
|
||||
#endif
|
||||
|
||||
+#ifdef SYMLINKS
|
||||
+ /* Initialize the symlink flag, may be set by the platform-specific
|
||||
+ mapattr function. */
|
||||
+ G.pInfo->symlink = 0;
|
||||
+#endif
|
||||
+
|
||||
return PK_COOL;
|
||||
|
||||
} /* end function process_cdir_file_hdr() */
|
||||
@@ -0,0 +1,41 @@
|
||||
From: "Steven M. Schweda" <[email protected]>
|
||||
Subject: Do not ignore extra fields containing Unix Timestamps
|
||||
Bug-Debian: https://bugs.debian.org/842993
|
||||
X-Debian-version: 6.0-21
|
||||
|
||||
--- a/process.c
|
||||
+++ b/process.c
|
||||
@@ -2914,10 +2914,13 @@
|
||||
break;
|
||||
|
||||
case EF_IZUNIX2:
|
||||
- if (have_new_type_eb == 0) {
|
||||
- flags &= ~0x0ff; /* ignore any previous IZUNIX field */
|
||||
+ if (have_new_type_eb == 0) { /* (< 1) */
|
||||
have_new_type_eb = 1;
|
||||
}
|
||||
+ if (have_new_type_eb <= 1) {
|
||||
+ /* Ignore any prior (EF_IZUNIX/EF_PKUNIX) UID/GID. */
|
||||
+ flags &= 0x0ff;
|
||||
+ }
|
||||
#ifdef IZ_HAVE_UXUIDGID
|
||||
if (have_new_type_eb > 1)
|
||||
break; /* IZUNIX3 overrides IZUNIX2 e.f. block ! */
|
||||
@@ -2933,6 +2936,8 @@
|
||||
/* new 3rd generation Unix ef */
|
||||
have_new_type_eb = 2;
|
||||
|
||||
+ /* Ignore any prior EF_IZUNIX/EF_PKUNIX/EF_IZUNIX2 UID/GID. */
|
||||
+ flags &= 0x0ff;
|
||||
/*
|
||||
Version 1 byte version of this extra field, currently 1
|
||||
UIDSize 1 byte Size of UID field
|
||||
@@ -2953,8 +2958,6 @@
|
||||
uid_size = *((EB_HEADSIZE + 1) + ef_buf);
|
||||
gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf);
|
||||
|
||||
- flags &= ~0x0ff; /* ignore any previous UNIX field */
|
||||
-
|
||||
if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf,
|
||||
uid_size, &z_uidgid[0])
|
||||
&&
|
||||
@@ -0,0 +1,26 @@
|
||||
diff --git a/fileio.c b/fileio.c
|
||||
index ba0a1d0..03fc4be 100644
|
||||
--- a/fileio.c
|
||||
+++ b/fileio.c
|
||||
@@ -2006,6 +2006,7 @@ int do_string(__G__ length, option) /* return PK-type error code */
|
||||
unsigned comment_bytes_left;
|
||||
unsigned int block_len;
|
||||
int error=PK_OK;
|
||||
+ unsigned int length2;
|
||||
#ifdef AMIGA
|
||||
char tmp_fnote[2 * AMIGA_FILENOTELEN]; /* extra room for squozen chars */
|
||||
#endif
|
||||
@@ -2292,8 +2293,12 @@ int do_string(__G__ length, option) /* return PK-type error code */
|
||||
seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
|
||||
(G.inptr-G.inbuf) + length);
|
||||
} else {
|
||||
- if (readbuf(__G__ (char *)G.extra_field, length) == 0)
|
||||
+ if ((length2 = readbuf(__G__ (char *)G.extra_field, length)) == 0)
|
||||
return PK_EOF;
|
||||
+ if(length2 < length) {
|
||||
+ memset (__G__ (char *)G.extra_field+length2, 0 , length-length2);
|
||||
+ length = length2;
|
||||
+ }
|
||||
/* Looks like here is where extra fields are read */
|
||||
getZip64Data(__G__ G.extra_field, length);
|
||||
#ifdef UNICODE_SUPPORT
|
||||
@@ -0,0 +1,28 @@
|
||||
--- ./process.c.orig 2009-03-06 02:25:10.000000000 +0100
|
||||
+++ ./process.c 2013-09-12 10:51:16.000000000 +0200
|
||||
@@ -2901,9 +2901,9 @@
|
||||
*/
|
||||
|
||||
#ifdef IZ_HAVE_UXUIDGID
|
||||
- if (eb_len >= EB_UX3_MINLEN
|
||||
- && z_uidgid != NULL
|
||||
- && (*((EB_HEADSIZE + 0) + ef_buf) == 1)
|
||||
+ if ((eb_len >= EB_UX3_MINLEN)
|
||||
+ && (z_uidgid != NULL)
|
||||
+ && ((*((EB_HEADSIZE + 0) + ef_buf) == 1)))
|
||||
/* only know about version 1 */
|
||||
{
|
||||
uch uid_size;
|
||||
@@ -2915,10 +2915,10 @@
|
||||
flags &= ~0x0ff; /* ignore any previous UNIX field */
|
||||
|
||||
if ( read_ux3_value((EB_HEADSIZE + 2) + ef_buf,
|
||||
- uid_size, z_uidgid[0])
|
||||
+ uid_size, &z_uidgid[0])
|
||||
&&
|
||||
read_ux3_value((EB_HEADSIZE + uid_size + 3) + ef_buf,
|
||||
- gid_size, z_uidgid[1]) )
|
||||
+ gid_size, &z_uidgid[1]) )
|
||||
{
|
||||
flags |= EB_UX2_VALID; /* signal success */
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
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));
|
||||
@@ -0,0 +1,25 @@
|
||||
From 6fe72291a5563cdbcd2bdd87e36528537b7cdcfb Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Martisko <[email protected]>
|
||||
Date: Mon, 18 Nov 2019 14:17:46 +0100
|
||||
Subject: [PATCH] update the man page
|
||||
|
||||
---
|
||||
man/unzip.1 | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/man/unzip.1 b/man/unzip.1
|
||||
index 21816d1..4d66073 100644
|
||||
--- a/man/unzip.1
|
||||
+++ b/man/unzip.1
|
||||
@@ -850,6 +850,8 @@ the specified zipfiles were not found.
|
||||
invalid options were specified on the command line.
|
||||
.IP 11
|
||||
no matching files were found.
|
||||
+.IP 12
|
||||
+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
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
From 41beb477c5744bc396fa1162ee0c14218ec12213 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Adler <[email protected]>
|
||||
Date: Mon, 27 May 2019 08:20:32 -0700
|
||||
Subject: [PATCH] Fix bug in undefer_input() that misplaced the input state.
|
||||
|
||||
---
|
||||
fileio.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/fileio.c b/fileio.c
|
||||
index c042987..bc00d74 100644
|
||||
--- a/fileio.c
|
||||
+++ b/fileio.c
|
||||
@@ -530,8 +530,10 @@ void undefer_input(__G)
|
||||
* This condition was checked when G.incnt_leftover was set > 0 in
|
||||
* defer_leftover_input(), and it is NOT allowed to touch G.csize
|
||||
* before calling undefer_input() when (G.incnt_leftover > 0)
|
||||
- * (single exception: see read_byte()'s "G.csize <= 0" handling) !!
|
||||
+ * (single exception: see readbyte()'s "G.csize <= 0" handling) !!
|
||||
*/
|
||||
+ if (G.csize < 0L)
|
||||
+ G.csize = 0L;
|
||||
G.incnt = G.incnt_leftover + (int)G.csize;
|
||||
G.inptr = G.inptr_leftover - (int)G.csize;
|
||||
G.incnt_leftover = 0;
|
||||
@@ -0,0 +1,349 @@
|
||||
From 47b3ceae397d21bf822bc2ac73052a4b1daf8e1c Mon Sep 17 00:00:00 2001
|
||||
From: Mark Adler <[email protected]>
|
||||
Date: Tue, 11 Jun 2019 22:01:18 -0700
|
||||
Subject: [PATCH] Detect and reject a zip bomb using overlapped entries.
|
||||
|
||||
This detects an invalid zip file that has at least one entry that
|
||||
overlaps with another entry or with the central directory to the
|
||||
end of the file. A Fifield zip bomb uses overlapped local entries
|
||||
to vastly increase the potential inflation ratio. Such an invalid
|
||||
zip file is rejected.
|
||||
|
||||
See https://www.bamsoftware.com/hacks/zipbomb/ for David Fifield's
|
||||
analysis, construction, and examples of such zip bombs.
|
||||
|
||||
The detection maintains a list of covered spans of the zip files
|
||||
so far, where the central directory to the end of the file and any
|
||||
bytes preceding the first entry at zip file offset zero are
|
||||
considered covered initially. Then as each entry is decompressed
|
||||
or tested, it is considered covered. When a new entry is about to
|
||||
be processed, its initial offset is checked to see if it is
|
||||
contained by a covered span. If so, the zip file is rejected as
|
||||
invalid.
|
||||
|
||||
This commit depends on a preceding commit: "Fix bug in
|
||||
undefer_input() that misplaced the input state."
|
||||
---
|
||||
extract.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
globals.c | 1 +
|
||||
globals.h | 3 +
|
||||
process.c | 11 ++++
|
||||
unzip.h | 1 +
|
||||
5 files changed, 205 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/extract.c b/extract.c
|
||||
index 1acd769..0973a33 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -319,6 +319,125 @@ static ZCONST char Far UnsupportedExtraField[] =
|
||||
"\nerror: unsupported extra-field compression type (%u)--skipping\n";
|
||||
static ZCONST char Far BadExtraFieldCRC[] =
|
||||
"error [%s]: bad extra-field CRC %08lx (should be %08lx)\n";
|
||||
+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";
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/* A growable list of spans. */
|
||||
+typedef zoff_t bound_t;
|
||||
+typedef struct {
|
||||
+ bound_t beg; /* start of the span */
|
||||
+ bound_t end; /* one past the end of the span */
|
||||
+} span_t;
|
||||
+typedef struct {
|
||||
+ span_t *span; /* allocated, distinct, and sorted list of spans */
|
||||
+ size_t num; /* number of spans in the list */
|
||||
+ size_t max; /* allocated number of spans (num <= max) */
|
||||
+} cover_t;
|
||||
+
|
||||
+/*
|
||||
+ * Return the index of the first span in cover whose beg is greater than val.
|
||||
+ * If there is no such span, then cover->num is returned.
|
||||
+ */
|
||||
+static size_t cover_find(cover, val)
|
||||
+ cover_t *cover;
|
||||
+ bound_t val;
|
||||
+{
|
||||
+ size_t lo = 0, hi = cover->num;
|
||||
+ while (lo < hi) {
|
||||
+ size_t mid = (lo + hi) >> 1;
|
||||
+ if (val < cover->span[mid].beg)
|
||||
+ hi = mid;
|
||||
+ else
|
||||
+ lo = mid + 1;
|
||||
+ }
|
||||
+ return hi;
|
||||
+}
|
||||
+
|
||||
+/* Return true if val lies within any one of the spans in cover. */
|
||||
+static int cover_within(cover, val)
|
||||
+ cover_t *cover;
|
||||
+ bound_t val;
|
||||
+{
|
||||
+ size_t pos = cover_find(cover, val);
|
||||
+ return pos > 0 && val < cover->span[pos - 1].end;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Add a new span to the list, but only if the new span does not overlap any
|
||||
+ * spans already in the list. The new span covers the values beg..end-1. beg
|
||||
+ * must be less than end.
|
||||
+ *
|
||||
+ * Keep the list sorted and merge adjacent spans. Grow the allocated space for
|
||||
+ * the list as needed. On success, 0 is returned. If the new span overlaps any
|
||||
+ * existing spans, then 1 is returned and the new span is not added to the
|
||||
+ * list. If the new span is invalid because beg is greater than or equal to
|
||||
+ * end, then -1 is returned. If the list needs to be grown but the memory
|
||||
+ * allocation fails, then -2 is returned.
|
||||
+ */
|
||||
+static int cover_add(cover, beg, end)
|
||||
+ cover_t *cover;
|
||||
+ bound_t beg;
|
||||
+ bound_t end;
|
||||
+{
|
||||
+ size_t pos;
|
||||
+ int prec, foll;
|
||||
+
|
||||
+ if (beg >= end)
|
||||
+ /* The new span is invalid. */
|
||||
+ return -1;
|
||||
+
|
||||
+ /* Find where the new span should go, and make sure that it does not
|
||||
+ overlap with any existing spans. */
|
||||
+ pos = cover_find(cover, beg);
|
||||
+ if ((pos > 0 && beg < cover->span[pos - 1].end) ||
|
||||
+ (pos < cover->num && end > cover->span[pos].beg))
|
||||
+ return 1;
|
||||
+
|
||||
+ /* Check for adjacencies. */
|
||||
+ prec = pos > 0 && beg == cover->span[pos - 1].end;
|
||||
+ foll = pos < cover->num && end == cover->span[pos].beg;
|
||||
+ if (prec && foll) {
|
||||
+ /* The new span connects the preceding and following spans. Merge the
|
||||
+ following span into the preceding span, and delete the following
|
||||
+ span. */
|
||||
+ cover->span[pos - 1].end = cover->span[pos].end;
|
||||
+ cover->num--;
|
||||
+ memmove(cover->span + pos, cover->span + pos + 1,
|
||||
+ (cover->num - pos) * sizeof(span_t));
|
||||
+ }
|
||||
+ else if (prec)
|
||||
+ /* The new span is adjacent only to the preceding span. Extend the end
|
||||
+ of the preceding span. */
|
||||
+ cover->span[pos - 1].end = end;
|
||||
+ else if (foll)
|
||||
+ /* The new span is adjacent only to the following span. Extend the
|
||||
+ beginning of the following span. */
|
||||
+ cover->span[pos].beg = beg;
|
||||
+ else {
|
||||
+ /* The new span has gaps between both the preceding and the following
|
||||
+ spans. Assure that there is room and insert the span. */
|
||||
+ if (cover->num == cover->max) {
|
||||
+ size_t max = cover->max == 0 ? 16 : cover->max << 1;
|
||||
+ span_t *span = realloc(cover->span, max * sizeof(span_t));
|
||||
+ if (span == NULL)
|
||||
+ return -2;
|
||||
+ cover->span = span;
|
||||
+ cover->max = max;
|
||||
+ }
|
||||
+ memmove(cover->span + pos + 1, cover->span + pos,
|
||||
+ (cover->num - pos) * sizeof(span_t));
|
||||
+ cover->num++;
|
||||
+ cover->span[pos].beg = beg;
|
||||
+ cover->span[pos].end = end;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
|
||||
|
||||
@@ -374,6 +493,29 @@ int extract_or_test_files(__G) /* return PK-type error code */
|
||||
}
|
||||
#endif /* !SFX || SFX_EXDIR */
|
||||
|
||||
+ /* One more: initialize cover structure for bomb detection. Start with a
|
||||
+ span that covers the central directory though the end of the file. */
|
||||
+ if (G.cover == NULL) {
|
||||
+ G.cover = malloc(sizeof(cover_t));
|
||||
+ if (G.cover == NULL) {
|
||||
+ 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 ((G.extra_bytes != 0 &&
|
||||
+ cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
|
||||
+ cover_add((cover_t *)G.cover,
|
||||
+ G.extra_bytes + G.ecrec.offset_start_central_directory,
|
||||
+ G.ziplen) != 0) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ LoadFarString(NotEnoughMemCover)));
|
||||
+ return PK_MEM;
|
||||
+ }
|
||||
+
|
||||
/*---------------------------------------------------------------------------
|
||||
The basic idea of this function is as follows. Since the central di-
|
||||
rectory lies at the end of the zipfile and the member files lie at the
|
||||
@@ -591,7 +733,8 @@ int extract_or_test_files(__G) /* return PK-type error code */
|
||||
if (error > error_in_archive)
|
||||
error_in_archive = error;
|
||||
/* ...and keep going (unless disk full or user break) */
|
||||
- if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
|
||||
+ if (G.disk_full > 1 || error_in_archive == IZ_CTRLC ||
|
||||
+ error == PK_BOMB) {
|
||||
/* clear reached_end to signal premature stop ... */
|
||||
reached_end = FALSE;
|
||||
/* ... and cancel scanning the central directory */
|
||||
@@ -1060,6 +1203,11 @@ 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)) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ LoadFarString(OverlappedComponents)));
|
||||
+ return PK_BOMB;
|
||||
+ }
|
||||
inbuf_offset = request % INBUFSIZ;
|
||||
bufstart = request - inbuf_offset;
|
||||
|
||||
@@ -1591,6 +1739,18 @@ static int extract_or_test_entrylist(__G__ numchunk,
|
||||
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) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ LoadFarString(NotEnoughMemCover)));
|
||||
+ return PK_MEM;
|
||||
+ }
|
||||
+ if (error != 0) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ LoadFarString(OverlappedComponents)));
|
||||
+ return PK_BOMB;
|
||||
+ }
|
||||
#ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
|
||||
UserStop();
|
||||
#endif
|
||||
@@ -1992,6 +2152,34 @@ 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.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)
|
||||
+ shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
|
||||
+ if (shy)
|
||||
+ error = PK_ERR;
|
||||
+ }
|
||||
+
|
||||
return error;
|
||||
|
||||
} /* end function extract_or_test_member() */
|
||||
diff --git a/globals.c b/globals.c
|
||||
index fa8cca5..1e0f608 100644
|
||||
--- a/globals.c
|
||||
+++ b/globals.c
|
||||
@@ -181,6 +181,7 @@ Uz_Globs *globalsCtor()
|
||||
# if (!defined(NO_TIMESTAMPS))
|
||||
uO.D_flag=1; /* default to '-D', no restoration of dir timestamps */
|
||||
# endif
|
||||
+ G.cover = NULL; /* not allocated yet */
|
||||
#endif
|
||||
|
||||
uO.lflag=(-1);
|
||||
diff --git a/globals.h b/globals.h
|
||||
index 11b7215..2bdcdeb 100644
|
||||
--- a/globals.h
|
||||
+++ b/globals.h
|
||||
@@ -260,12 +260,15 @@ 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 */
|
||||
int reported_backslash; /* extract.c static */
|
||||
int disk_full;
|
||||
int newfile;
|
||||
+ void **cover; /* used in extract.c for bomb detection */
|
||||
|
||||
int didCRlast; /* fileio static */
|
||||
ulg numlines; /* fileio static: number of lines printed */
|
||||
diff --git a/process.c b/process.c
|
||||
index 1e9a1e1..d2e4dc3 100644
|
||||
--- a/process.c
|
||||
+++ b/process.c
|
||||
@@ -637,6 +637,13 @@ void free_G_buffers(__G) /* releases all memory allocated in global vars */
|
||||
}
|
||||
#endif
|
||||
|
||||
+ /* Free the cover span list and the cover structure. */
|
||||
+ if (G.cover != NULL) {
|
||||
+ free(*(G.cover));
|
||||
+ free(G.cover);
|
||||
+ G.cover = NULL;
|
||||
+ }
|
||||
+
|
||||
} /* end function free_G_buffers() */
|
||||
|
||||
|
||||
@@ -1890,6 +1897,8 @@ 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;
|
||||
|
||||
@@ -1927,6 +1936,8 @@ int getZip64Data(__G__ ef_buf, ef_len)
|
||||
#if 0
|
||||
break; /* Expect only one EF_PKSZ64 block. */
|
||||
#endif /* 0 */
|
||||
+
|
||||
+ G.zip64 = TRUE;
|
||||
}
|
||||
|
||||
/* Skip this extra field block. */
|
||||
diff --git a/unzip.h b/unzip.h
|
||||
index 5b2a326..ed24a5b 100644
|
||||
--- a/unzip.h
|
||||
+++ b/unzip.h
|
||||
@@ -645,6 +645,7 @@ typedef struct _Uzp_cdir_Rec {
|
||||
#define PK_NOZIP 9 /* zipfile not found */
|
||||
#define PK_PARAM 10 /* bad or illegal parameters specified */
|
||||
#define PK_FIND 11 /* no files found */
|
||||
+#define PK_BOMB 12 /* likely zip bomb */
|
||||
#define PK_DISK 50 /* disk full */
|
||||
#define PK_EOF 51 /* unexpected EOF */
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
From 6d351831be705cc26d897db44f878a978f4138fc Mon Sep 17 00:00:00 2001
|
||||
From: Mark Adler <[email protected]>
|
||||
Date: Thu, 25 Jul 2019 20:43:17 -0700
|
||||
Subject: [PATCH] Do not raise a zip bomb alert for a misplaced central
|
||||
directory.
|
||||
|
||||
There is a zip-like file in the Firefox distribution, omni.ja,
|
||||
which is a zip container with the central directory placed at the
|
||||
start of the file instead of after the local entries as required
|
||||
by the zip standard. This commit marks the actual location of the
|
||||
central directory, as well as the end of central directory records,
|
||||
as disallowed locations. This now permits such containers to not
|
||||
raise a zip bomb alert, where in fact there are no overlaps.
|
||||
---
|
||||
extract.c | 25 +++++++++++++++++++------
|
||||
process.c | 6 ++++++
|
||||
unzpriv.h | 10 ++++++++++
|
||||
3 files changed, 35 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/extract.c b/extract.c
|
||||
index 0973a33..1b73cb0 100644
|
||||
--- a/extract.c
|
||||
+++ b/extract.c
|
||||
@@ -493,8 +493,11 @@ int extract_or_test_files(__G) /* return PK-type error code */
|
||||
}
|
||||
#endif /* !SFX || SFX_EXDIR */
|
||||
|
||||
- /* One more: initialize cover structure for bomb detection. Start with a
|
||||
- span that covers the central directory though the end of the file. */
|
||||
+ /* One more: initialize cover structure for bomb detection. Start with
|
||||
+ spans that cover any extra bytes at the start, the central directory,
|
||||
+ 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) {
|
||||
G.cover = malloc(sizeof(cover_t));
|
||||
if (G.cover == NULL) {
|
||||
@@ -506,15 +509,25 @@ int extract_or_test_files(__G) /* return PK-type error code */
|
||||
((cover_t *)G.cover)->max = 0;
|
||||
}
|
||||
((cover_t *)G.cover)->num = 0;
|
||||
- if ((G.extra_bytes != 0 &&
|
||||
- cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
|
||||
- cover_add((cover_t *)G.cover,
|
||||
+ if (cover_add((cover_t *)G.cover,
|
||||
G.extra_bytes + G.ecrec.offset_start_central_directory,
|
||||
- G.ziplen) != 0) {
|
||||
+ G.extra_bytes + G.ecrec.offset_start_central_directory +
|
||||
+ G.ecrec.size_central_directory) != 0) {
|
||||
Info(slide, 0x401, ((char *)slide,
|
||||
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) {
|
||||
+ Info(slide, 0x401, ((char *)slide,
|
||||
+ LoadFarString(OverlappedComponents)));
|
||||
+ return PK_BOMB;
|
||||
+ }
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
The basic idea of this function is as follows. Since the central di-
|
||||
diff --git a/process.c b/process.c
|
||||
index d2e4dc3..d75d405 100644
|
||||
--- a/process.c
|
||||
+++ b/process.c
|
||||
@@ -1408,6 +1408,10 @@ static int find_ecrec64(__G__ searchlen) /* return PK-class error */
|
||||
|
||||
/* Now, we are (almost) sure that we have a Zip64 archive. */
|
||||
G.ecrec.have_ecr64 = 1;
|
||||
+ G.ecrec.ec_start -= ECLOC64_SIZE+4;
|
||||
+ G.ecrec.ec64_start = ecrec64_start_offset;
|
||||
+ G.ecrec.ec64_end = ecrec64_start_offset +
|
||||
+ 12 + makeint64(&byterec[ECREC64_LENGTH]);
|
||||
|
||||
/* Update the "end-of-central-dir offset" for later checks. */
|
||||
G.real_ecrec_offset = ecrec64_start_offset;
|
||||
@@ -1542,6 +1546,8 @@ static int find_ecrec(__G__ searchlen) /* return PK-class error */
|
||||
makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
|
||||
G.ecrec.zipfile_comment_length =
|
||||
makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
|
||||
+ G.ecrec.ec_start = G.real_ecrec_offset;
|
||||
+ G.ecrec.ec_end = G.ecrec.ec_start + 22 + G.ecrec.zipfile_comment_length;
|
||||
|
||||
/* Now, we have to read the archive comment, BEFORE the file pointer
|
||||
is moved away backwards to seek for a Zip64 ECLOC64 structure.
|
||||
diff --git a/unzpriv.h b/unzpriv.h
|
||||
index dc9eff5..297b3c7 100644
|
||||
--- a/unzpriv.h
|
||||
+++ b/unzpriv.h
|
||||
@@ -2185,6 +2185,16 @@ typedef struct VMStimbuf {
|
||||
int have_ecr64; /* valid Zip64 ecdir-record exists */
|
||||
int is_zip64_archive; /* Zip64 ecdir-record is mandatory */
|
||||
ush zipfile_comment_length;
|
||||
+ zusz_t ec_start, ec_end; /* offsets of start and end of the
|
||||
+ end of central directory record,
|
||||
+ including if present the Zip64
|
||||
+ end of central directory locator,
|
||||
+ which immediately precedes the
|
||||
+ end of central directory record */
|
||||
+ zusz_t ec64_start, ec64_end; /* if have_ecr64 is true, then these
|
||||
+ are the offsets of the start and
|
||||
+ end of the Zip64 end of central
|
||||
+ directory record */
|
||||
} ecdir_rec;
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
From 5e2efcd633a4a1fb95a129a75508e7d769e767be Mon Sep 17 00:00:00 2001
|
||||
From: Mark Adler <[email protected]>
|
||||
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);
|
||||
@@ -0,0 +1,26 @@
|
||||
From 5c572555cf5d80309a07c30cf7a54b2501493720 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Adler <[email protected]>
|
||||
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);
|
||||
@@ -0,0 +1,95 @@
|
||||
From 122050bac16fae82a460ff739fb1ca0f106e9d85 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Adler <[email protected]>
|
||||
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
|
||||
@@ -0,0 +1,172 @@
|
||||
From af0d07f95809653b669d88aa0f424c6d5aa48ba0 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Adler <[email protected]>
|
||||
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;
|
||||
@@ -0,0 +1,202 @@
|
||||
From 5b44c818b96193b3e240f38f61985fa2bc780eb7 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Martisko <[email protected]>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user