]> git.ipfire.org Git - ipfire-3.x.git/commitdiff
unzip: Import latest patches from Fedora
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 30 Dec 2022 18:49:14 +0000 (18:49 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 30 Dec 2022 18:49:14 +0000 (18:49 +0000)
There have been no releases for unzip since 2009.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
31 files changed:
unzip/patches/0001-Fix-CVE-2016-9844-rhbz-1404283.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-COVSCAN-fix-unterminated-string.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-alt-iconv-utf8-print.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-alt-iconv-utf8.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-bzip2-configure.patch
unzip/patches/unzip-6.0-caseinsensitive.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-configure.patch [moved from unzip/patches/unzip-6.0-nostrip.patch with 93% similarity]
unzip/patches/unzip-6.0-cve-2014-8139.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-cve-2014-8140.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-cve-2014-8141.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-cve-2018-1000035-heap-based-overflow.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-cve-2018-18384.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-fix-recmatch.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-heap-overflow-infloop.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-manpage-fix.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-overflow-long-fsize.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-overflow.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-symlink.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-timestamp.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-valgrind.patch [new file with mode: 0644]
unzip/patches/unzip-6.0-x-option.patch [new file with mode: 0644]
unzip/patches/unzip-gnu89-build.patch [new file with mode: 0644]
unzip/patches/unzip-zipbomb-manpage.patch [new file with mode: 0644]
unzip/patches/unzip-zipbomb-part1.patch [new file with mode: 0644]
unzip/patches/unzip-zipbomb-part2.patch [new file with mode: 0644]
unzip/patches/unzip-zipbomb-part3.patch [new file with mode: 0644]
unzip/patches/unzip-zipbomb-part4.patch [new file with mode: 0644]
unzip/patches/unzip-zipbomb-part5.patch [new file with mode: 0644]
unzip/patches/unzip-zipbomb-part6.patch [new file with mode: 0644]
unzip/patches/unzip-zipbomb-switch.patch [new file with mode: 0644]
unzip/unzip.nm

diff --git a/unzip/patches/0001-Fix-CVE-2016-9844-rhbz-1404283.patch b/unzip/patches/0001-Fix-CVE-2016-9844-rhbz-1404283.patch
new file mode 100644 (file)
index 0000000..0e4a173
--- /dev/null
@@ -0,0 +1,39 @@
+From 754137e70cf58a64ad524b704a86b651ba0cde07 Mon Sep 17 00:00:00 2001
+From: Petr Stodulka <pstodulk@redhat.com>
+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
+
diff --git a/unzip/patches/unzip-6.0-COVSCAN-fix-unterminated-string.patch b/unzip/patches/unzip-6.0-COVSCAN-fix-unterminated-string.patch
new file mode 100644 (file)
index 0000000..7173771
--- /dev/null
@@ -0,0 +1,131 @@
+From 06d1b08aef94984256cad3c5a54cedb10295681f Mon Sep 17 00:00:00 2001
+From: Jakub Martisko <jamartis@redhat.com>
+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
+
diff --git a/unzip/patches/unzip-6.0-alt-iconv-utf8-print.patch b/unzip/patches/unzip-6.0-alt-iconv-utf8-print.patch
new file mode 100644 (file)
index 0000000..0b0153b
--- /dev/null
@@ -0,0 +1,381 @@
+From ca0212ba19b64488b9e8459a762c11ecd6e7d0bd Mon Sep 17 00:00:00 2001
+From: Petr Stodulka <pstodulk@redhat.com>
+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
+
diff --git a/unzip/patches/unzip-6.0-alt-iconv-utf8.patch b/unzip/patches/unzip-6.0-alt-iconv-utf8.patch
new file mode 100644 (file)
index 0000000..b9e3777
--- /dev/null
@@ -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 <marc.deslauriers@canonical.com>
+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  %c-T%c print file times in sortable decimal format\
++\n %c-C%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;
index 9cf006b8c78dc09fc5b6aea95840d3ed1ae75a35..b99bb4e4426c4373dbc2848921c7f0d197f2ff9f 100644 (file)
@@ -19,7 +19,7 @@ diff -up unzip60/unix/configure.bzip2-configure unzip60/unix/configure
 +    $CC $CFLAGS -o conftest conftest.c -lbz2 > /dev/null 2>/dev/null
 +    if test $? -eq 0; then
 +      echo "-- OS supports bzip2 - linking in bzip2"
-+      D_USE_BZ2="-DBZIP2_SUPPORT"
++      D_USE_BZ2="-DUSE_BZIP2"
 +      L_BZ2="${BZLF} -lbz2"
 +    else
 +      echo "-- Either bzlib.h or libbz2.a not found - no bzip2"
@@ -27,3 +27,4 @@ diff -up unzip60/unix/configure.bzip2-configure unzip60/unix/configure
    fi
  fi
  
\ No newline at end of file
diff --git a/unzip/patches/unzip-6.0-caseinsensitive.patch b/unzip/patches/unzip-6.0-caseinsensitive.patch
new file mode 100644 (file)
index 0000000..3cb6845
--- /dev/null
@@ -0,0 +1,131 @@
+diff --git a/match.c b/match.c
+index 6cd656f..4e569f5 100644
+--- a/match.c
++++ b/match.c
+@@ -190,10 +190,10 @@ char *___tmp_ptr;
+ #endif
+-static int recmatch(p, s, cs)
++static int recmatch(p, s, ci)
+ ZCONST char *p;         /* sh pattern to match */
+ ZCONST char *s;         /* string to match it to */
+-int cs;                 /* flag: force case-sensitive matching */
++int ci;                 /* flag: force case-insensitive matching */
+ /* Recursively compare the sh pattern p with the string s and return 1 if
+    they match, and 0 or 2 if they don't or if there is a syntax error in the
+    pattern.  This routine recurses on itself no deeper than the number of
+@@ -214,7 +214,7 @@ int cs;                 /* flag: force case-sensitive matching */
+   if (CLEN(p) == 2) {
+     if (CLEN(s) == 2) {
+       return (*p == *s && *(p+1) == *(s+1)) ?
+-        recmatch(p + 2, s + 2, cs) : 0;
++        recmatch(p + 2, s + 2, ci) : 0;
+     } else {
+       return 0;
+     }
+@@ -230,9 +230,9 @@ int cs;                 /* flag: force case-sensitive matching */
+   /* '?' (or '%' or '#') matches any character (but not an empty string) */
+   if (c == WILDCHR_SINGLE) {
+     if (wild_stop_at_dir)
+-      return (*s && *s != DIRSEP_CHR) ? recmatch(p, s + CLEN(s), cs) : 0;
++      return (*s && *s != DIRSEP_CHR) ? recmatch(p, s + CLEN(s), ci) : 0;
+     else
+-      return *s ? recmatch(p, s + CLEN(s), cs) : 0;
++      return *s ? recmatch(p, s + CLEN(s), ci) : 0;
+   }
+   /* WILDCHR_MULTI ('*') matches any number of characters, including zero */
+@@ -253,14 +253,14 @@ int cs;                 /* flag: force case-sensitive matching */
+ # endif /* ?AMIGA */
+         /* Single WILDCHR_MULTI ('*'): this doesn't match slashes */
+         for (; *s && *s != DIRSEP_CHR; INCSTR(s))
+-          if ((c = recmatch(p, s, cs)) != 0)
++          if ((c = recmatch(p, s, ci)) != 0)
+             return c;
+         /* end of pattern: matched if at end of string, else continue */
+         if (*p == 0)
+           return (*s == 0);
+         /* continue to match if at DIRSEP_CHR in pattern, else give up */
+         return (*p == DIRSEP_CHR || (*p == '\\' && p[1] == DIRSEP_CHR))
+-               ? recmatch(p, s, cs) : 2;
++               ? recmatch(p, s, ci) : 2;
+       }
+       /* Two consecutive WILDCHR_MULTI ("**"): this matches DIRSEP_CHR ('/') */
+       p++;        /* move p past the second WILDCHR_MULTI */
+@@ -308,17 +308,17 @@ int cs;                 /* flag: force case-sensitive matching */
+          */
+         if (q != srest)
+           return 0;
+-        return ((cs ? strcmp(p, q) : namecmp(p, q)) == 0);
++        return ((!ci ? strcmp(p, q) : namecmp(p, q)) == 0);
+       }
+ #else /* !_MBCS */
+-        return ((cs ? strcmp(p, srest) : namecmp(p, srest)) == 0);
++        return ((!ci ? strcmp(p, srest) : namecmp(p, srest)) == 0);
+ #endif /* ?_MBCS */
+     }
+     else
+     {
+       /* pattern contains more wildcards, continue with recursion... */
+       for (; *s; INCSTR(s))
+-        if ((c = recmatch(p, s, cs)) != 0)
++        if ((c = recmatch(p, s, ci)) != 0)
+           return c;
+       return 2;           /* 2 means give up--shmatch will return false */
+     }
+@@ -353,17 +353,17 @@ int cs;                 /* flag: force case-sensitive matching */
+         c = *(p-1);
+       else
+       {
+-        uch cc = (cs ? (uch)*s : case_map((uch)*s));
++        uch cc = (!ci ? (uch)*s : to_up((uch)*s));
+         uch uc = (uch) c;
+         if (*(p+1) != '-')
+           for (uc = uc ? uc : (uch)*p; uc <= (uch)*p; uc++)
+             /* compare range */
+-            if ((cs ? uc : case_map(uc)) == cc)
+-              return r ? 0 : recmatch(q + CLEN(q), s + CLEN(s), cs);
++            if ((!ci ? uc : to_up(uc)) == cc)
++              return r ? 0 : recmatch(q + CLEN(q), s + CLEN(s), ci);
+         c = e = 0;                      /* clear range, escape flags */
+       }
+     }
+-    return r ? recmatch(q + CLEN(q), s + CLEN(s), cs) : 0;
++    return r ? recmatch(q + CLEN(q), s + CLEN(s), ci) : 0;
+                                         /* bracket match failed */
+   }
+ #endif /* !VMS */
+@@ -382,18 +382,18 @@ int cs;                 /* flag: force case-sensitive matching */
+   {
+     /* Match "...]" with "]".  Continue after "]" in both. */
+     if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
+-      return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs);
++      return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), ci);
+     /* Else, look for a reduced match in s, until "]" in or end of s. */
+     for (; *s && (*s != ']'); INCSTR(s))
+       if (*s == '.')
+         /* If reduced match, then continue after "..." in p, "." in s. */
+-        if ((c = recmatch( (p+ CLEN( p)), s, cs)) != 0)
++        if ((c = recmatch( (p+ CLEN( p)), s, ci)) != 0)
+           return (int)c;
+     /* Match "...]" with "]".  Continue after "]" in both. */
+     if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
+-      return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs);
++      return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), ci);
+     /* No reduced match.  Quit. */
+     return 2;
+@@ -402,8 +402,8 @@ int cs;                 /* flag: force case-sensitive matching */
+ #endif /* def VMS */
+   /* Just a character--compare it */
+-  return (cs ? c == *s : case_map((uch)c) == case_map((uch)*s)) ?
+-          recmatch(p, s + CLEN(s), cs) : 0;
++  return (!ci ? c == *s : to_up((uch)c) == to_up((uch)*s)) ?
++          recmatch(p, s + CLEN(s), ci) : 0;
+ }
similarity index 93%
rename from unzip/patches/unzip-6.0-nostrip.patch
rename to unzip/patches/unzip-6.0-configure.patch
index 71c263f69cc581a9661e2fa61e1db8205a16a20a..9eead4227c2ebaa982a26203b1b340e939afbb67 100644 (file)
@@ -6,7 +6,7 @@ diff -up unzip60/unix/configure.nostrip unzip60/unix/configure
  CFLAGS="${CFLAGS} -I. -DUNIX"
  LFLAGS1=""
 -LFLAGS2="-s"
-+LFLAGS2=""
++LFLAGS2="${LFLAGS2}"
  LN="ln -s"
  
  CFLAGS_OPT=''
diff --git a/unzip/patches/unzip-6.0-cve-2014-8139.patch b/unzip/patches/unzip-6.0-cve-2014-8139.patch
new file mode 100644 (file)
index 0000000..226b35a
--- /dev/null
@@ -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 */
+
diff --git a/unzip/patches/unzip-6.0-cve-2014-8140.patch b/unzip/patches/unzip-6.0-cve-2014-8140.patch
new file mode 100644 (file)
index 0000000..b9eba92
--- /dev/null
@@ -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))
diff --git a/unzip/patches/unzip-6.0-cve-2014-8141.patch b/unzip/patches/unzip-6.0-cve-2014-8141.patch
new file mode 100644 (file)
index 0000000..584c576
--- /dev/null
@@ -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);
+     }
diff --git a/unzip/patches/unzip-6.0-cve-2018-1000035-heap-based-overflow.patch b/unzip/patches/unzip-6.0-cve-2018-1000035-heap-based-overflow.patch
new file mode 100644 (file)
index 0000000..8ca7138
--- /dev/null
@@ -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);
diff --git a/unzip/patches/unzip-6.0-cve-2018-18384.patch b/unzip/patches/unzip-6.0-cve-2018-18384.patch
new file mode 100644 (file)
index 0000000..54d4b8c
--- /dev/null
@@ -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"),
diff --git a/unzip/patches/unzip-6.0-fix-recmatch.patch b/unzip/patches/unzip-6.0-fix-recmatch.patch
new file mode 100644 (file)
index 0000000..2a8583c
--- /dev/null
@@ -0,0 +1,477 @@
+diff -up unzip60/match.c.recmatch unzip60/match.c
+--- unzip60/match.c.recmatch   2005-08-14 13:00:36.000000000 -0400
++++ unzip60/match.c    2013-05-28 10:29:57.949077543 -0400
+@@ -27,16 +27,14 @@
+   ---------------------------------------------------------------------------
+-  Copyright on recmatch() from Zip's util.c (although recmatch() was almost
+-  certainly written by Mark Adler...ask me how I can tell :-) ):
++  Copyright on recmatch() from Zip's util.c
++       Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
+-     Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
+-     Kai Uwe Rommel and Igor Mandrichenko.
++       See the accompanying file LICENSE, version 2004-May-22 or later
++       for terms of use.
++       If, for some reason, both of these files are missing, the Info-ZIP license
++       also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html  
+-     Permission is granted to any individual or institution to use, copy,
+-     or redistribute this software so long as all of the original files are
+-     included unmodified, that it is not sold for profit, and that this copy-
+-     right notice is retained.
+   ---------------------------------------------------------------------------
+@@ -53,7 +51,7 @@
+   A set is composed of characters or ranges; a range looks like ``character
+   hyphen character'' (as in 0-9 or A-Z).  [0-9a-zA-Z_] is the minimal set of
+-  characters allowed in the [..] pattern construct.  Other characters are
++  characters ALlowed in the [..] pattern construct.  Other characters are
+   allowed (i.e., 8-bit characters) if your system will support them.
+   To suppress the special syntactic significance of any of ``[]*?!^-\'', in-
+@@ -101,8 +99,32 @@
+ #  define WILDCHAR   '?'
+ #  define BEG_RANGE  '['
+ #  define END_RANGE  ']'
++#  define WILDCHR_SINGLE '?'
++#  define DIRSEP_CHR '/'
++#  define WILDCHR_MULTI '*'
+ #endif
++#ifdef WILD_STOP_AT_DIR
++   int wild_stop_at_dir = 1; /* default wildcards do not include / in matches */
++#else
++   int wild_stop_at_dir = 0; /* default wildcards do include / in matches */
++#endif
++
++
++
++/*
++ * case mapping functions. case_map is used to ignore case in comparisons,
++ * to_up is used to force upper case even on Unix (for dosify option).
++ */
++#ifdef USE_CASE_MAP
++#  define case_map(c) upper[(c) & 0xff]
++#  define to_up(c)    upper[(c) & 0xff]
++#else
++#  define case_map(c) (c)
++#  define to_up(c)    ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c))
++#endif /* USE_CASE_MAP */
++
++
+ #if 0                /* GRR:  add this to unzip.h someday... */
+ #if !(defined(MSDOS) && defined(DOSWILD))
+ #ifdef WILD_STOP_AT_DIR
+@@ -114,8 +136,8 @@ int recmatch OF((ZCONST uch *pattern, ZC
+                  int ignore_case __WDLPRO));
+ #endif
+ #endif /* 0 */
+-static int recmatch OF((ZCONST uch *pattern, ZCONST uch *string,
+-                        int ignore_case __WDLPRO));
++static int recmatch OF((ZCONST char *, ZCONST char *, 
++                        int));
+ static char *isshexp OF((ZCONST char *p));
+ static int namecmp OF((ZCONST char *s1, ZCONST char *s2));
+@@ -154,192 +176,240 @@ int match(string, pattern, ignore_case _
+             }
+             dospattern[j-1] = '\0';                    /* nuke the end "." */
+         }
+-        j = recmatch((uch *)dospattern, (uch *)string, ignore_case __WDL);
++        j = recmatch(dospattern, string, ignore_case);
+         free(dospattern);
+         return j == 1;
+     } else
+ #endif /* MSDOS && DOSWILD */
+-    return recmatch((uch *)pattern, (uch *)string, ignore_case __WDL) == 1;
++    return recmatch(pattern, string, ignore_case) == 1;
+ }
++#ifdef _MBCS
++
++char *___tmp_ptr;
++#endif
+-static int recmatch(p, s, ic __WDL)
+-    ZCONST uch *p;        /* sh pattern to match */
+-    ZCONST uch *s;        /* string to which to match it */
+-    int ic;               /* true for case insensitivity */
+-    __WDLDEF              /* directory sepchar for WildStopAtDir mode, or 0 */
++static int recmatch(p, s, cs)
++ZCONST char *p;         /* sh pattern to match */
++ZCONST char *s;         /* string to match it to */
++int cs;                 /* flag: force case-sensitive matching */
+ /* Recursively compare the sh pattern p with the string s and return 1 if
+- * they match, and 0 or 2 if they don't or if there is a syntax error in the
+- * pattern.  This routine recurses on itself no more deeply than the number
+- * of characters in the pattern. */
++   they match, and 0 or 2 if they don't or if there is a syntax error in the
++   pattern.  This routine recurses on itself no deeper than the number of
++   characters in the pattern. */
+ {
+-    unsigned int c;       /* pattern char or start of range in [-] loop */
++  int c;                /* pattern char or start of range in [-] loop */
++  /* Get first character, the pattern for new recmatch calls follows */
++ /* borrowed from Zip's global.c */
++ int no_wild = 0; 
++ int allow_regex=1;
++  /* This fix provided by akt@m5.dion.ne.jp for Japanese.
++     See 21 July 2006 mail.
++     It only applies when p is pointing to a doublebyte character and
++     things like / and wildcards are not doublebyte.  This probably
++     should not be needed. */
+-    /* Get first character, the pattern for new recmatch calls follows */
+-    c = *p; INCSTR(p);
++#ifdef _MBCS
++  if (CLEN(p) == 2) {
++    if (CLEN(s) == 2) {
++      return (*p == *s && *(p+1) == *(s+1)) ?
++        recmatch(p + 2, s + 2, cs) : 0;
++    } else {
++      return 0;
++    }
++  }
++#endif /* ?_MBCS */
+-    /* If that was the end of the pattern, match if string empty too */
+-    if (c == 0)
+-        return *s == 0;
++  c = *POSTINCSTR(p);
+-    /* '?' (or '%') matches any character (but not an empty string). */
+-    if (c == WILDCHAR)
+-#ifdef WILD_STOP_AT_DIR
+-        /* If uO.W_flag is non-zero, it won't match '/' */
+-        return (*s && (!sepc || *s != (uch)sepc))
+-               ? recmatch(p, s + CLEN(s), ic, sepc) : 0;
+-#else
+-        return *s ? recmatch(p, s + CLEN(s), ic) : 0;
+-#endif
++  /* If that was the end of the pattern, match if string empty too */
++  if (c == 0)
++    return *s == 0;
++
++  /* '?' (or '%' or '#') matches any character (but not an empty string) */
++  if (c == WILDCHR_SINGLE) {
++    if (wild_stop_at_dir)
++      return (*s && *s != DIRSEP_CHR) ? recmatch(p, s + CLEN(s), cs) : 0;
++    else
++      return *s ? recmatch(p, s + CLEN(s), cs) : 0;
++  }
+-    /* '*' matches any number of characters, including zero */
++  /* WILDCHR_MULTI ('*') matches any number of characters, including zero */
+ #ifdef AMIGA
+-    if (c == '#' && *p == '?')     /* "#?" is Amiga-ese for "*" */
+-        c = '*', p++;
++  if (!no_wild && c == '#' && *p == '?')            /* "#?" is Amiga-ese for "*" */
++    c = WILDCHR_MULTI, p++;
+ #endif /* AMIGA */
+-    if (c == '*') {
+-#ifdef WILD_STOP_AT_DIR
+-        if (sepc) {
+-          /* check for single "*" or double "**" */
+-#  ifdef AMIGA
+-          if ((c = p[0]) == '#' && p[1] == '?') /* "#?" is Amiga-ese for "*" */
+-            c = '*', p++;
+-          if (c != '*') {
+-#  else /* !AMIGA */
+-          if (*p != '*') {
+-#  endif /* ?AMIGA */
+-            /* single "*": this doesn't match the dirsep character */
+-            for (; *s && *s != (uch)sepc; INCSTR(s))
+-                if ((c = recmatch(p, s, ic, sepc)) != 0)
+-                    return (int)c;
+-            /* end of pattern: matched if at end of string, else continue */
+-            if (*p == '\0')
+-                return (*s == 0);
+-            /* continue to match if at sepc in pattern, else give up */
+-            return (*p == (uch)sepc || (*p == '\\' && p[1] == (uch)sepc))
+-                   ? recmatch(p, s, ic, sepc) : 2;
+-          }
+-          /* "**": this matches slashes */
+-          ++p;        /* move p behind the second '*' */
+-          /* and continue with the non-W_flag code variant */
+-        }
+-#endif /* WILD_STOP_AT_DIR */
++  if (!no_wild && c == WILDCHR_MULTI)
++  {
++    if (wild_stop_at_dir) {
++      /* Check for an immediately following WILDCHR_MULTI */
++# ifdef AMIGA
++      if ((c = p[0]) == '#' && p[1] == '?') /* "#?" is Amiga-ese for "*" */
++        c = WILDCHR_MULTI, p++;
++      if (c != WILDCHR_MULTI) {
++# else /* !AMIGA */
++      if (*p != WILDCHR_MULTI) {
++# endif /* ?AMIGA */
++        /* Single WILDCHR_MULTI ('*'): this doesn't match slashes */
++        for (; *s && *s != DIRSEP_CHR; INCSTR(s))
++          if ((c = recmatch(p, s, cs)) != 0)
++            return c;
++        /* end of pattern: matched if at end of string, else continue */
+         if (*p == 0)
+-            return 1;
+-        if (isshexp((ZCONST char *)p) == NULL) {
+-            /* Optimization for rest of pattern being a literal string:
+-             * If there are no other shell expression chars in the rest
+-             * of the pattern behind the multi-char wildcard, then just
+-             * compare the literal string tail.
+-             */
+-            ZCONST uch *srest;
+-
+-            srest = s + (strlen((ZCONST char *)s) - strlen((ZCONST char *)p));
+-            if (srest - s < 0)
+-                /* remaining literal string from pattern is longer than rest
+-                 * of test string, there can't be a match
+-                 */
+-                return 0;
+-            else
+-              /* compare the remaining literal pattern string with the last
+-               * bytes of the test string to check for a match
+-               */
++          return (*s == 0);
++        /* continue to match if at DIRSEP_CHR in pattern, else give up */
++        return (*p == DIRSEP_CHR || (*p == '\\' && p[1] == DIRSEP_CHR))
++               ? recmatch(p, s, cs) : 2;
++      }
++      /* Two consecutive WILDCHR_MULTI ("**"): this matches DIRSEP_CHR ('/') */
++      p++;        /* move p past the second WILDCHR_MULTI */
++      /* continue with the normal non-WILD_STOP_AT_DIR code */
++    } /* wild_stop_at_dir */
++
++    /* Not wild_stop_at_dir */
++    if (*p == 0)
++      return 1;
++    if (!isshexp((char *)p))
++    {
++      /* optimization for rest of pattern being a literal string */
++
++      /* optimization to handle patterns like *.txt */
++      /* if the first char in the pattern is '*' and there */
++      /* are no other shell expression chars, i.e. a literal string */
++      /* then just compare the literal string at the end */
++
++      ZCONST char *srest;
++
++      srest = s + (strlen(s) - strlen(p));
++      if (srest - s < 0)
++        /* remaining literal string from pattern is longer than rest of
++           test string, there can't be a match
++         */
++        return 0;
++      else
++        /* compare the remaining literal pattern string with the last bytes
++           of the test string to check for a match */
+ #ifdef _MBCS
+-            {
+-                ZCONST uch *q = s;
++      {
++        ZCONST char *q = s;
+-                /* MBCS-aware code must not scan backwards into a string from
+-                 * the end.
+-                 * So, we have to move forward by character from our well-known
+-                 * character position s in the test string until we have
+-                 * advanced to the srest position.
+-                 */
+-                while (q < srest)
+-                  INCSTR(q);
+-                /* In case the byte *srest is a trailing byte of a multibyte
+-                 * character in the test string s, we have actually advanced
+-                 * past the position (srest).
+-                 * For this case, the match has failed!
+-                 */
+-                if (q != srest)
+-                    return 0;
+-                return ((ic
+-                         ? namecmp((ZCONST char *)p, (ZCONST char *)q)
+-                         : strcmp((ZCONST char *)p, (ZCONST char *)q)
+-                        ) == 0);
+-            }
++        /* MBCS-aware code must not scan backwards into a string from
++         * the end.
++         * So, we have to move forward by character from our well-known
++         * character position s in the test string until we have advanced
++         * to the srest position.
++         */
++        while (q < srest)
++          INCSTR(q);
++        /* In case the byte *srest is a trailing byte of a multibyte
++         * character, we have actually advanced past the position (srest).
++         * For this case, the match has failed!
++         */
++        if (q != srest)
++          return 0;
++        return ((cs ? strcmp(p, q) : namecmp(p, q)) == 0);
++      }
+ #else /* !_MBCS */
+-                return ((ic
+-                         ? namecmp((ZCONST char *)p, (ZCONST char *)srest)
+-                         : strcmp((ZCONST char *)p, (ZCONST char *)srest)
+-                        ) == 0);
++        return ((cs ? strcmp(p, srest) : namecmp(p, srest)) == 0);
+ #endif /* ?_MBCS */
+-        } else {
+-            /* pattern contains more wildcards, continue with recursion... */
+-            for (; *s; INCSTR(s))
+-                if ((c = recmatch(p, s, ic __WDL)) != 0)
+-                    return (int)c;
+-            return 2;  /* 2 means give up--match will return false */
+-        }
+     }
+-
+-    /* Parse and process the list of characters and ranges in brackets */
+-    if (c == BEG_RANGE) {
+-        int e;          /* flag true if next char to be taken literally */
+-        ZCONST uch *q;  /* pointer to end of [-] group */
+-        int r;          /* flag true to match anything but the range */
+-
+-        if (*s == 0)                            /* need a character to match */
+-            return 0;
+-        p += (r = (*p == '!' || *p == '^'));    /* see if reverse */
+-        for (q = p, e = 0; *q; INCSTR(q))       /* find closing bracket */
+-            if (e)
+-                e = 0;
+-            else
+-                if (*q == '\\')      /* GRR:  change to ^ for MS-DOS, OS/2? */
+-                    e = 1;
+-                else if (*q == END_RANGE)
+-                    break;
+-        if (*q != END_RANGE)         /* nothing matches if bad syntax */
+-            return 0;
+-        for (c = 0, e = (*p == '-'); p < q; INCSTR(p)) {
+-            /* go through the list */
+-            if (!e && *p == '\\')               /* set escape flag if \ */
+-                e = 1;
+-            else if (!e && *p == '-')           /* set start of range if - */
+-                c = *(p-1);
+-            else {
+-                unsigned int cc = Case(*s);
+-
+-                if (*(p+1) != '-')
+-                    for (c = c ? c : *p; c <= *p; c++)  /* compare range */
+-                        if ((unsigned)Case(c) == cc) /* typecast for MSC bug */
+-                            return r ? 0 : recmatch(q + 1, s + 1, ic __WDL);
+-                c = e = 0;   /* clear range, escape flags */
+-            }
+-        }
+-        return r ? recmatch(q + CLEN(q), s + CLEN(s), ic __WDL) : 0;
+-                                        /* bracket match failed */
++    else
++    {
++      /* pattern contains more wildcards, continue with recursion... */
++      for (; *s; INCSTR(s))
++        if ((c = recmatch(p, s, cs)) != 0)
++          return c;
++      return 2;           /* 2 means give up--shmatch will return false */
+     }
++  }
+-    /* if escape ('\\'), just compare next character */
+-    if (c == '\\' && (c = *p++) == 0)     /* if \ at end, then syntax error */
+-        return 0;
++#ifndef VMS             /* No bracket matching in VMS */
++  /* Parse and process the list of characters and ranges in brackets */
++  if (!no_wild && allow_regex && c == '[')
++  {
++    int e;              /* flag true if next char to be taken literally */
++    ZCONST char *q;     /* pointer to end of [-] group */
++    int r;              /* flag true to match anything but the range */
++
++    if (*s == 0)                        /* need a character to match */
++      return 0;
++    p += (r = (*p == '!' || *p == '^')); /* see if reverse */
++    for (q = p, e = 0; *q; q++)         /* find closing bracket */
++      if (e)
++        e = 0;
++      else
++        if (*q == '\\')
++          e = 1;
++        else if (*q == ']')
++          break;
++    if (*q != ']')                      /* nothing matches if bad syntax */
++      return 0;
++    for (c = 0, e = *p == '-'; p < q; p++)      /* go through the list */
++    {
++      if (e == 0 && *p == '\\')         /* set escape flag if \ */
++        e = 1;
++      else if (e == 0 && *p == '-')     /* set start of range if - */
++        c = *(p-1);
++      else
++      {
++        uch cc = (cs ? (uch)*s : case_map((uch)*s));
++        uch uc = (uch) c;
++        if (*(p+1) != '-')
++          for (uc = uc ? uc : (uch)*p; uc <= (uch)*p; uc++)
++            /* compare range */
++            if ((cs ? uc : case_map(uc)) == cc)
++              return r ? 0 : recmatch(q + CLEN(q), s + CLEN(s), cs);
++        c = e = 0;                      /* clear range, escape flags */
++      }
++    }
++    return r ? recmatch(q + CLEN(q), s + CLEN(s), cs) : 0;
++                                        /* bracket match failed */
++  }
++#endif /* !VMS */
+-    /* just a character--compare it */
+-#ifdef QDOS
+-    return QMatch(Case((uch)c), Case(*s)) ?
+-           recmatch(p, s + CLEN(s), ic __WDL) : 0;
+-#else
+-    return Case((uch)c) == Case(*s) ?
+-           recmatch(p, s + CLEN(s), ic __WDL) : 0;
+-#endif
++  /* If escape ('\'), just compare next character */
++  if (!no_wild && c == '\\')
++    if ((c = *p++) == '\0')             /* if \ at end, then syntax error */
++      return 0;
++
++#ifdef VMS
++  /* 2005-11-06 SMS.
++     Handle "..." wildcard in p with "." or "]" in s.
++  */
++  if ((c == '.') && (*p == '.') && (*(p+ CLEN( p)) == '.') &&
++   ((*s == '.') || (*s == ']')))
++  {
++    /* Match "...]" with "]".  Continue after "]" in both. */
++    if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
++      return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs);
++
++    /* Else, look for a reduced match in s, until "]" in or end of s. */
++    for (; *s && (*s != ']'); INCSTR(s))
++      if (*s == '.')
++        /* If reduced match, then continue after "..." in p, "." in s. */
++        if ((c = recmatch( (p+ CLEN( p)), s, cs)) != 0)
++          return (int)c;
++
++    /* Match "...]" with "]".  Continue after "]" in both. */
++    if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
++      return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs);
++
++    /* No reduced match.  Quit. */
++    return 2;
++  }
++
++#endif /* def VMS */
++
++  /* Just a character--compare it */
++  return (cs ? c == *s : case_map((uch)c) == case_map((uch)*s)) ?
++          recmatch(p, s + CLEN(s), cs) : 0;
++}
+-} /* end function recmatch() */
++/*************************************************************************************************/
+ static char *isshexp(p)
+ ZCONST char *p;
+ /* If p is a sh expression, a pointer to the first special character is
diff --git a/unzip/patches/unzip-6.0-heap-overflow-infloop.patch b/unzip/patches/unzip-6.0-heap-overflow-infloop.patch
new file mode 100644 (file)
index 0000000..b517c40
--- /dev/null
@@ -0,0 +1,104 @@
+From bdd4a0cecd745cb4825e4508b5bdf2579731086a Mon Sep 17 00:00:00 2001
+From: Petr Stodulka <pstodulk@redhat.com>
+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 <kdudka@redhat.com>
+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 <kdudka@redhat.com>
+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
+
diff --git a/unzip/patches/unzip-6.0-manpage-fix.patch b/unzip/patches/unzip-6.0-manpage-fix.patch
new file mode 100644 (file)
index 0000000..ec06516
--- /dev/null
@@ -0,0 +1,11 @@
+--- unzip60/man/unzip.1        2011-01-11 11:59:59.000000000 +0000
++++ unzip60/man/unzip_new      2011-02-05 18:45:55.000000000 +0000
+@@ -424,7 +424,7 @@
+ .\" Amiga support possible eventually, but not yet
+ [MS-DOS, OS/2, NT] restore the volume label if the extraction medium is
+ removable (e.g., a diskette).  Doubling the option (\fB\-$$\fP) allows fixed
+-media (hard disks) to be labelled as well.  By default, volume labels are
++media (hard disks) to be labeled as well.  By default, volume labels are
+ ignored.
+ .IP \fB\-/\fP\ \fIextensions\fP
+ [Acorn only] overrides the extension list supplied by Unzip$Ext environment
diff --git a/unzip/patches/unzip-6.0-overflow-long-fsize.patch b/unzip/patches/unzip-6.0-overflow-long-fsize.patch
new file mode 100644 (file)
index 0000000..80cd708
--- /dev/null
@@ -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? */
diff --git a/unzip/patches/unzip-6.0-overflow.patch b/unzip/patches/unzip-6.0-overflow.patch
new file mode 100644 (file)
index 0000000..228c283
--- /dev/null
@@ -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) ||
diff --git a/unzip/patches/unzip-6.0-symlink.patch b/unzip/patches/unzip-6.0-symlink.patch
new file mode 100644 (file)
index 0000000..d7eaf16
--- /dev/null
@@ -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() */
diff --git a/unzip/patches/unzip-6.0-timestamp.patch b/unzip/patches/unzip-6.0-timestamp.patch
new file mode 100644 (file)
index 0000000..2aa9424
--- /dev/null
@@ -0,0 +1,41 @@
+From: "Steven M. Schweda" <sms@antinode.info>
+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])
+                     &&
diff --git a/unzip/patches/unzip-6.0-valgrind.patch b/unzip/patches/unzip-6.0-valgrind.patch
new file mode 100644 (file)
index 0000000..41a7520
--- /dev/null
@@ -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
diff --git a/unzip/patches/unzip-6.0-x-option.patch b/unzip/patches/unzip-6.0-x-option.patch
new file mode 100644 (file)
index 0000000..72c77ae
--- /dev/null
@@ -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 */
+                 }
diff --git a/unzip/patches/unzip-gnu89-build.patch b/unzip/patches/unzip-gnu89-build.patch
new file mode 100644 (file)
index 0000000..706f125
--- /dev/null
@@ -0,0 +1,15 @@
+unzip uses C89-only features, so it needs to be built in C89 mode.
+
+diff --git a/unix/Makefile b/unix/Makefile
+index ab32270cf4b9b2cf..5eabbe13095e1f58 100644
+--- a/unix/Makefile
++++ b/unix/Makefile
+@@ -545,7 +545,7 @@ generic:   flags      # now try autoconfigure first
+ #     make $(MAKEF) unzips CF="${CF} `cat flags`"
+ generic_gcc:
+-      $(MAKE) $(MAKEF) generic CC=gcc IZ_BZIP2="$(IZ_BZIP2)"
++      $(MAKE) $(MAKEF) generic CC="gcc -std=gnu89" IZ_BZIP2="$(IZ_BZIP2)"
+ # extensions to perform SVR4 package-creation after compilation
+ generic_pkg:  generic svr4package
diff --git a/unzip/patches/unzip-zipbomb-manpage.patch b/unzip/patches/unzip-zipbomb-manpage.patch
new file mode 100644 (file)
index 0000000..bcee827
--- /dev/null
@@ -0,0 +1,25 @@
+From 6fe72291a5563cdbcd2bdd87e36528537b7cdcfb Mon Sep 17 00:00:00 2001
+From: Jakub Martisko <jamartis@redhat.com>
+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
+
diff --git a/unzip/patches/unzip-zipbomb-part1.patch b/unzip/patches/unzip-zipbomb-part1.patch
new file mode 100644 (file)
index 0000000..35cf856
--- /dev/null
@@ -0,0 +1,25 @@
+From 41beb477c5744bc396fa1162ee0c14218ec12213 Mon Sep 17 00:00:00 2001
+From: Mark Adler <madler@alumni.caltech.edu>
+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;
diff --git a/unzip/patches/unzip-zipbomb-part2.patch b/unzip/patches/unzip-zipbomb-part2.patch
new file mode 100644 (file)
index 0000000..903c845
--- /dev/null
@@ -0,0 +1,349 @@
+From 47b3ceae397d21bf822bc2ac73052a4b1daf8e1c Mon Sep 17 00:00:00 2001
+From: Mark Adler <madler@alumni.caltech.edu>
+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 */
diff --git a/unzip/patches/unzip-zipbomb-part3.patch b/unzip/patches/unzip-zipbomb-part3.patch
new file mode 100644 (file)
index 0000000..3b8d67b
--- /dev/null
@@ -0,0 +1,112 @@
+From 6d351831be705cc26d897db44f878a978f4138fc Mon Sep 17 00:00:00 2001
+From: Mark Adler <madler@alumni.caltech.edu>
+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;
diff --git a/unzip/patches/unzip-zipbomb-part4.patch b/unzip/patches/unzip-zipbomb-part4.patch
new file mode 100644 (file)
index 0000000..beffa2c
--- /dev/null
@@ -0,0 +1,25 @@
+From 5e2efcd633a4a1fb95a129a75508e7d769e767be Mon Sep 17 00:00:00 2001
+From: Mark Adler <madler@alumni.caltech.edu>
+Date: Sun, 9 Feb 2020 20:36:28 -0800
+Subject: [PATCH] Fix bug in UZbunzip2() that incorrectly updated G.incnt.
+
+The update assumed a full buffer, which is not always full. This
+could result in a false overlapped element detection when a small
+bzip2-compressed file was unzipped. This commit remedies that.
+---
+ extract.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/extract.c b/extract.c
+index d9866f9..0cb7bfc 100644
+--- a/extract.c
++++ b/extract.c
+@@ -3010,7 +3010,7 @@ __GDEF
+ #endif
+     G.inptr = (uch *)bstrm.next_in;
+-    G.incnt = (G.inbuf + INBUFSIZ) - G.inptr;  /* reset for other routines */
++    G.incnt -= G.inptr - G.inbuf;       /* reset for other routines */
+ uzbunzip_cleanup_exit:
+     err = BZ2_bzDecompressEnd(&bstrm);
diff --git a/unzip/patches/unzip-zipbomb-part5.patch b/unzip/patches/unzip-zipbomb-part5.patch
new file mode 100644 (file)
index 0000000..ca6a43a
--- /dev/null
@@ -0,0 +1,26 @@
+From 5c572555cf5d80309a07c30cf7a54b2501493720 Mon Sep 17 00:00:00 2001
+From: Mark Adler <madler@alumni.caltech.edu>
+Date: Sun, 9 Feb 2020 21:39:09 -0800
+Subject: [PATCH] Fix bug in UZinflate() that incorrectly updated G.incnt.
+
+The update assumed a full buffer, which is not always full. This
+could result in a false overlapped element detection when a small
+deflate-compressed file was unzipped using an old zlib. This
+commit remedies that.
+---
+ inflate.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/inflate.c b/inflate.c
+index 2f5a015..70e3cc0 100644
+--- a/inflate.c
++++ b/inflate.c
+@@ -700,7 +700,7 @@ int UZinflate(__G__ is_defl64)
+       G.dstrm.total_out));
+     G.inptr = (uch *)G.dstrm.next_in;
+-    G.incnt = (G.inbuf + INBUFSIZ) - G.inptr;  /* reset for other routines */
++    G.incnt -= G.inptr - G.inbuf;       /* reset for other routines */
+ uzinflate_cleanup_exit:
+     err = inflateReset(&G.dstrm);
diff --git a/unzip/patches/unzip-zipbomb-part6.patch b/unzip/patches/unzip-zipbomb-part6.patch
new file mode 100644 (file)
index 0000000..3dce6e3
--- /dev/null
@@ -0,0 +1,95 @@
+From 122050bac16fae82a460ff739fb1ca0f106e9d85 Mon Sep 17 00:00:00 2001
+From: Mark Adler <madler@alumni.caltech.edu>
+Date: Sat, 2 Jan 2021 13:09:34 -0800
+Subject: [PATCH] Determine Zip64 status entry-by-entry instead of for entire
+ file.
+
+Fixes a bug for zip files with mixed Zip64 and not Zip64 entries,
+which resulted in an incorrect data descriptor length. The bug is
+seen when a Zip64 entry precedes a non-Zip64 entry, in which case
+the data descriptor would have been assumed to be larger than it
+is, resulting in an incorrect bomb warning due to a perceived
+overlap with the next entry. This commit determines and saves the
+Zip64 status for each entry based on the central directory, and
+then computes the length of each data descriptor accordingly.
+---
+ extract.c | 5 +++--
+ globals.h | 2 --
+ process.c | 4 +---
+ unzpriv.h | 1 +
+ 4 files changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/extract.c b/extract.c
+index 504afd6..878817d 100644
+--- a/extract.c
++++ b/extract.c
+@@ -658,6 +658,7 @@ int extract_or_test_files(__G)    /* return PK-type error code */
+                     break;
+                 }
+             }
++            G.pInfo->zip64 = FALSE;
+             if ((error = do_string(__G__ G.crec.extra_field_length,
+                 EXTRA_FIELD)) != 0)
+             {
+@@ -2187,12 +2188,12 @@ static int extract_or_test_member(__G)    /* return PK-type error code */
+              (clen == SIG &&                    /* if not SIG, no signature */
+               ((G.lrec.csize & LOW) != SIG ||   /* if not SIG, have signature */
+                (ulen == SIG &&                  /* if not SIG, no signature */
+-                (G.zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
++                (G.pInfo->zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
+                                                 /* if not SIG, have signature */
+                 )))))
+                    /* skip four more bytes to account for signature */
+                    shy += 4 - readbuf((char *)buf, 4);
+-        if (G.zip64)
++        if (G.pInfo->zip64)
+             shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
+         if (shy)
+             error = PK_ERR;
+diff --git a/globals.h b/globals.h
+index f9c6daf..a883c90 100644
+--- a/globals.h
++++ b/globals.h
+@@ -261,8 +261,6 @@ typedef struct Globals {
+     ecdir_rec       ecrec;         /* used in unzip.c, extract.c */
+     z_stat   statbuf;              /* used by main, mapname, check_for_newer */
+-    int zip64;                     /* true if Zip64 info in extra field */
+-
+     int      mem_mode;
+     uch      *outbufptr;           /* extract.c static */
+     ulg      outsize;              /* extract.c static */
+diff --git a/process.c b/process.c
+index d75d405..d643c6f 100644
+--- a/process.c
++++ b/process.c
+@@ -1903,8 +1903,6 @@ int getZip64Data(__G__ ef_buf, ef_len)
+ #define Z64FLGS 0xffff
+ #define Z64FLGL 0xffffffff
+-    G.zip64 = FALSE;
+-
+     if (ef_len == 0 || ef_buf == NULL)
+         return PK_COOL;
+@@ -1943,7 +1941,7 @@ int getZip64Data(__G__ ef_buf, ef_len)
+           break;                /* Expect only one EF_PKSZ64 block. */
+ #endif /* 0 */
+-          G.zip64 = TRUE;
++          G.pInfo->zip64 = TRUE;
+         }
+         /* Skip this extra field block. */
+diff --git a/unzpriv.h b/unzpriv.h
+index 09f288e..75b3359 100644
+--- a/unzpriv.h
++++ b/unzpriv.h
+@@ -2034,6 +2034,7 @@ typedef struct min_info {
+ #ifdef UNICODE_SUPPORT
+     unsigned GPFIsUTF8: 1;   /* crec gen_purpose_flag UTF-8 bit 11 is set */
+ #endif
++    unsigned zip64: 1;       /* true if entry has Zip64 extra block */
+ #ifndef SFX
+     char Far *cfilname;      /* central header version of filename */
+ #endif
diff --git a/unzip/patches/unzip-zipbomb-switch.patch b/unzip/patches/unzip-zipbomb-switch.patch
new file mode 100644 (file)
index 0000000..c6d33c0
--- /dev/null
@@ -0,0 +1,215 @@
+From 5b44c818b96193b3e240f38f61985fa2bc780eb7 Mon Sep 17 00:00:00 2001
+From: Jakub Martisko <jamartis@redhat.com>
+Date: Tue, 30 Nov 2021 15:42:17 +0100
+Subject: [PATCH] Add an option to disable the zipbomb detection
+
+This can be done by settting a newly introduced environment variable
+UNZIP_DISABLE_ZIPBOMB_DETECTION to {TRUE,True,true}. If the variable is unset, or
+set to any other value the zipbomb detection is left enabled.
+
+Example:
+       UNZIP_DISABLE_ZIPBOMB_DETECTION=True unzip ./zbsm.zip -d ./test
+---
+ extract.c | 85 ++++++++++++++++++++++++++++++-------------------------
+ unzip.c   | 15 ++++++++--
+ unzip.h   |  1 +
+ 3 files changed, 60 insertions(+), 41 deletions(-)
+
+diff --git a/extract.c b/extract.c
+index 878817d..3e58071 100644
+--- a/extract.c
++++ b/extract.c
+@@ -322,7 +322,8 @@ static ZCONST char Far BadExtraFieldCRC[] =
+ static ZCONST char Far NotEnoughMemCover[] =
+   "error: not enough memory for bomb detection\n";
+ static ZCONST char Far OverlappedComponents[] =
+-  "error: invalid zip file with overlapped components (possible zip bomb)\n";
++  "error: invalid zip file with overlapped components (possible zip bomb)\n \
++To unzip the file anyway, rerun the command with UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE environmnent variable\n";
+@@ -502,35 +503,37 @@ int extract_or_test_files(__G)    /* return PK-type error code */
+        the end of central directory record (including the Zip64 end of central
+        directory locator, if present), and the Zip64 end of central directory
+        record, if present. */
+-    if (G.cover == NULL) {
++    if (uO.zipbomb == TRUE) {
++      if (G.cover == NULL) {
+         G.cover = malloc(sizeof(cover_t));
+         if (G.cover == NULL) {
+-            Info(slide, 0x401, ((char *)slide,
+-              LoadFarString(NotEnoughMemCover)));
+-            return PK_MEM;
++            Info(slide, 0x401, ((char *)slide,
++              LoadFarString(NotEnoughMemCover)));
++            return PK_MEM;
+         }
+         ((cover_t *)G.cover)->span = NULL;
+         ((cover_t *)G.cover)->max = 0;
+-    }
+-    ((cover_t *)G.cover)->num = 0;
+-    if (cover_add((cover_t *)G.cover,
+-                  G.extra_bytes + G.ecrec.offset_start_central_directory,
+-                  G.extra_bytes + G.ecrec.offset_start_central_directory +
+-                  G.ecrec.size_central_directory) != 0) {
++    }
++    ((cover_t *)G.cover)->num = 0;
++    if (cover_add((cover_t *)G.cover,
++                  G.extra_bytes + G.ecrec.offset_start_central_directory,
++                  G.extra_bytes + G.ecrec.offset_start_central_directory +
++                  G.ecrec.size_central_directory) != 0) {
+         Info(slide, 0x401, ((char *)slide,
+-          LoadFarString(NotEnoughMemCover)));
++          LoadFarString(NotEnoughMemCover)));
+         return PK_MEM;
+-    }
+-    if ((G.extra_bytes != 0 &&
+-         cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
+-        (G.ecrec.have_ecr64 &&
+-         cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
+-                   G.ecrec.ec64_end) != 0) ||
+-        cover_add((cover_t *)G.cover, G.ecrec.ec_start,
+-                  G.ecrec.ec_end) != 0) {
++    }
++    if ((G.extra_bytes != 0 &&
++         cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
++        (G.ecrec.have_ecr64 &&
++         cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
++                   G.ecrec.ec64_end) != 0) ||
++        cover_add((cover_t *)G.cover, G.ecrec.ec_start,
++                  G.ecrec.ec_end) != 0) {
+         Info(slide, 0x401, ((char *)slide,
+-          LoadFarString(OverlappedComponents)));
++          LoadFarString(OverlappedComponents)));
+         return PK_BOMB;
++      }
+     }
+ /*---------------------------------------------------------------------------
+@@ -1222,10 +1225,12 @@ static int extract_or_test_entrylist(__G__ numchunk,
+         /* seek_zipf(__G__ pInfo->offset);  */
+         request = G.pInfo->offset + G.extra_bytes;
+-        if (cover_within((cover_t *)G.cover, request)) {
++        if (uO.zipbomb == TRUE) {
++          if (cover_within((cover_t *)G.cover, request)) {
+             Info(slide, 0x401, ((char *)slide,
+-              LoadFarString(OverlappedComponents)));
++              LoadFarString(OverlappedComponents)));
+             return PK_BOMB;
++          }
+         }
+         inbuf_offset = request % INBUFSIZ;
+         bufstart = request - inbuf_offset;
+@@ -1758,17 +1763,19 @@ reprompt:
+             return IZ_CTRLC;        /* cancel operation by user request */
+         }
+ #endif
+-        error = cover_add((cover_t *)G.cover, request,
+-                          G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
+-        if (error < 0) {
++        if (uO.zipbomb == TRUE) {
++          error = cover_add((cover_t *)G.cover, request,
++                            G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
++          if (error < 0) {
+             Info(slide, 0x401, ((char *)slide,
+-              LoadFarString(NotEnoughMemCover)));
++                                LoadFarString(NotEnoughMemCover)));
+             return PK_MEM;
+-        }
+-        if (error != 0) {
++          }
++          if (error != 0) {
+             Info(slide, 0x401, ((char *)slide,
+-              LoadFarString(OverlappedComponents)));
++                                LoadFarString(OverlappedComponents)));
+             return PK_BOMB;
++          }
+         }
+ #ifdef MACOS  /* MacOS is no preemptive OS, thus call event-handling by hand */
+         UserStop();
+@@ -2171,8 +2178,8 @@ static int extract_or_test_member(__G)    /* return PK-type error code */
+     }
+     undefer_input(__G);
+-
+-    if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
++    if (uO.zipbomb == TRUE) {
++      if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
+         /* skip over data descriptor (harder than it sounds, due to signature
+          * ambiguity)
+          */
+@@ -2189,16 +2196,16 @@ static int extract_or_test_member(__G)    /* return PK-type error code */
+               ((G.lrec.csize & LOW) != SIG ||   /* if not SIG, have signature */
+                (ulen == SIG &&                  /* if not SIG, no signature */
+                 (G.pInfo->zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
+-                                                /* if not SIG, have signature */
++                /* if not SIG, have signature */
+                 )))))
+-                   /* skip four more bytes to account for signature */
+-                   shy += 4 - readbuf((char *)buf, 4);
++          /* skip four more bytes to account for signature */
++          shy += 4 - readbuf((char *)buf, 4);
+         if (G.pInfo->zip64)
+-            shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
++          shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
+         if (shy)
+-            error = PK_ERR;
++          error = PK_ERR;
++      }
+     }
+-
+     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
+
index ea4581544779d4344fb9b42c1cfdef98196990b6..664790074e567298f5d61a076a807bad711180fb 100644 (file)
@@ -5,10 +5,11 @@
 
 name       = unzip
 version    = 6.0
-release    = 5
+release    = 6
+thisapp    = %{name}60
 
 groups     = Applications/Archiving
-url        = ftp://ftp.info-zip.org/pub/infozip/src/
+url        = https://infozip.sourceforge.net/UnZip.html
 license    = BSD
 summary    = A utility for unpacking zip files.
 
@@ -21,14 +22,53 @@ description
        in some respects.
 end
 
-thisapp    = %{name}60
 
-source_dl += ftp://ftp.info-zip.org/pub/infozip/src/
-sources    = %{thisapp}.tgz
+source_dl += https://downloads.sourceforge.net/infozip/
+
+patches
+       unzip-6.0-bzip2-configure.patch
+       unzip-6.0-exec-shield.patch
+       unzip-6.0-close.patch
+       unzip-6.0-attribs-overflow.patch
+       unzip-6.0-configure.patch
+       unzip-6.0-manpage-fix.patch
+       unzip-6.0-fix-recmatch.patch
+       unzip-6.0-symlink.patch
+       unzip-6.0-caseinsensitive.patch
+       unzip-6.0-format-secure.patch
+       unzip-6.0-valgrind.patch
+       unzip-6.0-x-option.patch
+       unzip-6.0-overflow.patch
+       unzip-6.0-cve-2014-8139.patch
+       unzip-6.0-cve-2014-8140.patch
+       unzip-6.0-cve-2014-8141.patch
+       unzip-6.0-overflow-long-fsize.patch
+       unzip-6.0-heap-overflow-infloop.patch
+       unzip-6.0-alt-iconv-utf8.patch
+       unzip-6.0-alt-iconv-utf8-print.patch
+       0001-Fix-CVE-2016-9844-rhbz-1404283.patch
+       unzip-6.0-timestamp.patch
+       unzip-6.0-cve-2018-1000035-heap-based-overflow.patch
+       unzip-6.0-cve-2018-18384.patch
+       unzip-6.0-COVSCAN-fix-unterminated-string.patch
+       unzip-zipbomb-part1.patch
+       unzip-zipbomb-part2.patch
+       unzip-zipbomb-part3.patch
+       unzip-zipbomb-manpage.patch
+       unzip-zipbomb-part4.patch
+       unzip-zipbomb-part5.patch
+       unzip-zipbomb-part6.patch
+       unzip-zipbomb-switch.patch
+       unzip-gnu89-build.patch
+end
 
 CFLAGS    += -D_LARGEFILE64_SOURCE
 
 build
+       requires
+               bzip2-devel
+       end
+
        DIR_APP = %{DIR_SRC}/%{thisapp}
 
        build