[unzip] Fixes few security bugs and overflow on long file sizes

pstodulk pstodulk at fedoraproject.org
Tue Feb 10 20:27:43 UTC 2015


commit f6883dfa8599e8b93a75c8f85f08879be28a5910
Author: Petr Stodulka <pstodulk at redhat.com>
Date:   Tue Feb 10 21:26:05 2015 +0100

    Fixes few security bugs and overflow on long file sizes

 unzip-6.0-cve-2014-8139.patch       |   79 ++++++++++++++++++++
 unzip-6.0-cve-2014-8140.patch       |   25 ++++++
 unzip-6.0-cve-2014-8141.patch       |  138 +++++++++++++++++++++++++++++++++++
 unzip-6.0-overflow-long-fsize.patch |   34 +++++++++
 unzip.spec                          |   20 +++++-
 5 files changed, 295 insertions(+), 1 deletions(-)
---
diff --git a/unzip-6.0-cve-2014-8139.patch b/unzip-6.0-cve-2014-8139.patch
new file mode 100644
index 0000000..226b35a
--- /dev/null
+++ b/unzip-6.0-cve-2014-8139.patch
@@ -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-6.0-cve-2014-8140.patch b/unzip-6.0-cve-2014-8140.patch
new file mode 100644
index 0000000..148cca6
--- /dev/null
+++ b/unzip-6.0-cve-2014-8140.patch
@@ -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_ucsize))
diff --git a/unzip-6.0-cve-2014-8141.patch b/unzip-6.0-cve-2014-8141.patch
new file mode 100644
index 0000000..584c576
--- /dev/null
+++ b/unzip-6.0-cve-2014-8141.patch
@@ -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-6.0-overflow-long-fsize.patch b/unzip-6.0-overflow-long-fsize.patch
new file mode 100644
index 0000000..80cd708
--- /dev/null
+++ b/unzip-6.0-overflow-long-fsize.patch
@@ -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.spec b/unzip.spec
index ce892ea..bf2a6b4 100644
--- a/unzip.spec
+++ b/unzip.spec
@@ -1,7 +1,7 @@
 Summary: A utility for unpacking zip files
 Name: unzip
 Version: 6.0
-Release: 18%{?dist}
+Release: 19%{?dist}
 License: BSD
 Group: Applications/Archiving
 Source: http://downloads.sourceforge.net/infozip/unzip60.tar.gz
@@ -32,6 +32,10 @@ Patch10: unzip-6.0-format-secure.patch
 Patch11: unzip-6.0-valgrind.patch
 Patch12: unzip-6.0-x-option.patch
 Patch13: unzip-6.0-overflow.patch
+Patch14: unzip-6.0-cve-2014-8139.patch
+Patch15: unzip-6.0-cve-2014-8140.patch
+Patch16: unzip-6.0-cve-2014-8141.patch
+Patch17: unzip-6.0-overflow-long-fsize.patch
 URL: http://www.info-zip.org/UnZip.html
 BuildRequires:  bzip2-devel
 
@@ -61,6 +65,10 @@ a zip archive.
 %patch11 -p1 -b .valgrind
 %patch12 -p1 -b .x-option
 %patch13 -p1 -b .overflow
+%patch14 -p1 -b .cve-2014-8139
+%patch15 -p1 -b .cve-2014-8140
+%patch16 -p1 -b .cve-2014-8141
+%patch17 -p1 -b .overflow-long-fsize
 
 %build
 # IZ_HAVE_UXUIDGID is needed for right functionality of unzip -X
@@ -79,6 +87,16 @@ make -f unix/Makefile prefix=$RPM_BUILD_ROOT%{_prefix} MANDIR=$RPM_BUILD_ROOT/%{
 %{_mandir}/*/*
 
 %changelog
+* Tue Feb 10 2015 Petr Stodulka <pstodulk at redhat.com> - 6.0-19
+- Fix CVE-2014-8139 - CRC32 verification heap-based buffer overread 
+  (#1174844)
+- Fix CVE-2014-8140 - out-of-bounds write issue in test_compr_eb()
+  (#1174851)
+- Fix CVE-2014-8141 - getZip64Data() out-of-bounds read issues
+  (#1174856)
+- Fix buffer overflow on long file sizes
+  (#1191136)
+
 * Mon Jan 26 2015 Petr Stodulka <pstodulk at redhat.com> - 6.0-18
 - Fix security bug - CVE-2014-9636
 


More information about the scm-commits mailing list