changeset 452:8c4366128400

compression/unzip: initial import, closes #1553
author David Demelier <markand@malikania.fr>
date Sat, 06 Apr 2019 08:13:23 +0200
parents bcfdaa03daa2
children dc81a1fa4b2e
files compression/unzip/CVE-2014-8139.patch compression/unzip/CVE-2014-8140.patch compression/unzip/CVE-2014-8141.patch compression/unzip/CVE-2014-9636.patch compression/unzip/CVE-2014-9913.patch compression/unzip/CVE-2016-9844.patch compression/unzip/CVE-2018-1000035.patch compression/unzip/unzip.sh
diffstat 8 files changed, 421 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compression/unzip/CVE-2014-8139.patch	Sat Apr 06 08:13:23 2019 +0200
@@ -0,0 +1,75 @@
+--- 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 @@
+ #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))
+@@ -2032,7 +2034,8 @@
+         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 ",
+@@ -2167,11 +2170,29 @@
+                 }
+                 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:
+--- 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 */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compression/unzip/CVE-2014-8140.patch	Sat Apr 06 08:13:23 2019 +0200
@@ -0,0 +1,26 @@
+From RedHat: https://bugzilla.redhat.com/attachment.cgi?id=969621&action=diff
+(unzip60/ path prefix added)
+
+--- unzip60/extract.c	2009-03-14 02:32:52.000000000 +0100
++++ unzip60/extract.c	2014-12-05 22:43:13.000000000 +0100
+@@ -2221,10 +2234,17 @@ static int test_compr_eb(__G__ eb, eb_si
+     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! */
+ 
+     if (
+ #ifdef INT_16BIT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compression/unzip/CVE-2014-8141.patch	Sat Apr 06 08:13:23 2019 +0200
@@ -0,0 +1,136 @@
+From RedHat: https://bugzilla.redhat.com/attachment.cgi?id=969625&action=diff
+(unzip60/ path prefix added)
+
+--- unzip60/process.c	2009-03-06 02:25:10.000000000 +0100
++++ unzip60/process.c	2014-12-05 22:42:39.000000000 +0100
+@@ -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.
+@@ -1888,48 +1888,82 @@ 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);
+     }
+--- unzip60/fileio.c	2009-04-20 02:03:44.000000000 +0200
++++ unzip60/fileio.c	2014-12-05 22:44:16.000000000 +0100
+@@ -176,6 +176,8 @@ static ZCONST char Far FilenameTooLongTr
+ #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[] =
+@@ -2295,7 +2297,12 @@ int do_string(__G__ length, option)   /*
+             if (readbuf(__G__ (char *)G.extra_field, length) == 0)
+                 return PK_EOF;
+             /* 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) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compression/unzip/CVE-2014-9636.patch	Sat Apr 06 08:13:23 2019 +0200
@@ -0,0 +1,42 @@
+From 190040ebfcf5395a6ccedede2cc9343d34f0a108 Mon Sep 17 00:00:00 2001
+From: mancha <mancha1 AT zoho DOT com>
+Date: Wed, 11 Feb 2015
+Subject: Info-ZIP UnZip buffer overflow
+
+By carefully crafting a corrupt ZIP archive with "extra fields" that
+purport to have compressed blocks larger than the corresponding
+uncompressed blocks in STORED no-compression mode, an attacker can
+trigger a heap overflow that can result in application crash or
+possibly have other unspecified impact.
+
+This patch ensures that when extra fields use STORED mode, the
+"compressed" and uncompressed block sizes match.
+
+---
+ extract.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/extract.c
++++ b/extract.c
+@@ -2217,6 +2217,7 @@ static int test_compr_eb(__G__ eb, eb_si
+     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 */
+@@ -2226,6 +2227,13 @@ static int test_compr_eb(__G__ eb, eb_si
+          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) ||
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compression/unzip/CVE-2014-9913.patch	Sat Apr 06 08:13:23 2019 +0200
@@ -0,0 +1,29 @@
+From: "Steven M. Schweda" <sms@antinode.info>
+Subject: Fix CVE-2014-9913, buffer overflow in unzip
+Bug: https://sourceforge.net/p/infozip/bugs/27/
+Bug-Debian: https://bugs.debian.org/847485
+Bug-Ubuntu: https://launchpad.net/bugs/387350
+X-Debian-version: 6.0-21
+
+--- a/list.c
++++ b/list.c
+@@ -339,7 +339,18 @@
+                 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/p/infozip/bugs/27/  CVE-2014-9913.
++                 * 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? */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compression/unzip/CVE-2016-9844.patch	Sat Apr 06 08:13:23 2019 +0200
@@ -0,0 +1,28 @@
+From: "Steven M. Schweda" <sms@antinode.info>
+Subject: Fix CVE-2016-9844, buffer overflow in zipinfo
+Bug-Debian: https://bugs.debian.org/847486
+Bug-Ubuntu: https://launchpad.net/bugs/1643750
+X-Debian-version: 6.0-21
+
+--- a/zipinfo.c
++++ b/zipinfo.c
+@@ -1921,7 +1921,18 @@
+         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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compression/unzip/CVE-2018-1000035.patch	Sat Apr 06 08:13:23 2019 +0200
@@ -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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compression/unzip/unzip.sh	Sat Apr 06 08:13:23 2019 +0200
@@ -0,0 +1,51 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+PKGNAME=unzip
+PKGVERSION=6.0
+PKGREVISION=1
+PKGLICENSE="CUSTOM"
+PKGSUMMARY="utility to decompress zip files"
+PKGDOWNLOAD="https://downloads.sourceforge.net/infozip/${PKGNAME}60.tar.gz"
+PKGDEPENDS="core/bzip2"
+
+: ${CC:=clang}
+
+build()
+{
+	rm -rf ${PKGNAME}60
+	tar xvaf ${PKGNAME}60.tar.gz
+	pushd ${PKGNAME}60
+
+	patch -p1 < ../CVE-2014-8139.patch
+	patch -p1 < ../CVE-2014-8140.patch
+	patch -p1 < ../CVE-2014-8141.patch
+	patch -p1 < ../CVE-2014-9636.patch
+	patch -p1 < ../CVE-2014-9913.patch
+	patch -p1 < ../CVE-2016-9844.patch
+	patch -p1 < ../CVE-2018-1000035.patch
+
+	# does not support DESTDIR, fake it with prefix.
+	make -f unix/Makefile CC="$CC" generic
+	make -f unix/Makefile \
+		prefix=$DESTDIR/usr \
+		MANDIR=$DESTDIR/usr/share/man/man1 \
+		install
+
+	popd
+	rm -rf ${PKGNAME}60
+}