This has fixes for

CVE-2014-8139: CRC32 verification heap-based overflow
CVE-2014-8140: out-of-bounds write issue in test_compr_eb()
CVE-2014-8141: out-of-bounds read issues in getZip64Data()
CVE-2014-9636: out-of-bounds read/write in test_compr_eb()

The diffs are taken more or less blindly from the Debian package.
I gave up on trying to track them down to the original mailing
lists, forum posts, bug tracker reports, initial versions, updated
versions, ...

This could use some testing.  It will have to go into -stable, too.

Index: Makefile
===================================================================
RCS file: /cvs/ports/archivers/unzip/Makefile,v
retrieving revision 1.51
diff -u -p -r1.51 Makefile
--- Makefile    9 Dec 2014 22:51:35 -0000       1.51
+++ Makefile    5 Feb 2015 21:03:57 -0000
@@ -5,7 +5,7 @@ COMMENT=        extract, list & test files in a
 VERSION=       6.0
 DISTNAME=      unzip${VERSION:S/.//}
 PKGNAME=       unzip-${VERSION}
-REVISION =     5
+REVISION =     6
 CATEGORIES=    archivers
 MASTER_SITES=  ${MASTER_SITE_SOURCEFORGE:=infozip/} \
                ftp://ftp.info-zip.org/pub/infozip/src/
Index: patches/patch-extract_c
===================================================================
RCS file: patches/patch-extract_c
diff -N patches/patch-extract_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-extract_c     5 Feb 2015 21:03:57 -0000
@@ -0,0 +1,89 @@
+$OpenBSD$
+
+Fix CVE-2014-8139: CRC32 verification heap-based overflow
+Fix CVE-2014-8140: out-of-bounds write issue in test_compr_eb()
+Fix CVE-2014-9636: out-of-bounds read/write in test_compr_eb()
+
+--- extract.c.orig     Sat Mar 14 02:32:52 2009
++++ extract.c  Thu Feb  5 18:58:23 2015
+@@ -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))
+@@ -2023,7 +2025,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 ",
+@@ -2158,11 +2161,19 @@ static int TestExtraField(__G__ ef, ef_len)
+                 }
+                 break;
+             case EF_PKVMS:
+-                if (makelong(ef+EB_HEADSIZE) !=
++                if (ebLen < 4)
++                {
++                    Info(slide, 1,
++                     ((char *)slide, LoadFarString(TooSmallEBlength),
++                     ebLen, 4));
++                }
++                else if (makelong(ef+EB_HEADSIZE) !=
+                     crc32(CRCVAL_INITIAL, ef+(EB_HEADSIZE+4),
+                           (extent)(ebLen-4)))
++                {
+                     Info(slide, 1, ((char *)slide,
+                       LoadFarString(BadCRC_EAs)));
++                }
+                 break;
+             case EF_PKW32:
+             case EF_PKUNIX:
+@@ -2217,14 +2228,30 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offs
+     ulg eb_ucsize;
+     uch *eb_ucptr;
+     int r;
++    ush eb_compr_method;
+ 
+     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! */
++
++    /* 2014-11-03 Michal Zalewski, SMS.
++     * For STORE method, compressed and uncompressed sizes must agree.
++     * http://www.info-zip.org/phpBB3/viewtopic.php?f=7&t=450
++     */
++    eb_compr_method = makeword( eb + (EB_HEADSIZE + compr_offset));
++    if ((eb_compr_method == STORED) && (eb_size - compr_offset != eb_ucsize))
++        return PK_ERR;
+ 
+     if (
+ #ifdef INT_16BIT
Index: patches/patch-fileio_c
===================================================================
RCS file: patches/patch-fileio_c
diff -N patches/patch-fileio_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-fileio_c      5 Feb 2015 21:03:57 -0000
@@ -0,0 +1,29 @@
+$OpenBSD$
+
+Fix CVE-2014-8141: out-of-bounds read issues in getZip64Data()
+
+--- fileio.c.orig      Mon Apr 20 02:03:44 2009
++++ fileio.c   Thu Feb  5 18:57:59 2015
+@@ -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[] =
+@@ -2295,7 +2297,12 @@ int do_string(__G__ length, option)   /* return PK-typ
+             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) {
Index: patches/patch-process_c
===================================================================
RCS file: /cvs/ports/archivers/unzip/patches/patch-process_c,v
retrieving revision 1.1
diff -u -p -r1.1 patch-process_c
--- patches/patch-process_c     9 Jan 2014 15:22:45 -0000       1.1
+++ patches/patch-process_c     5 Feb 2015 21:03:57 -0000
@@ -1,6 +1,17 @@
 $OpenBSD: patch-process_c,v 1.1 2014/01/09 15:22:45 naddy Exp $
+
+Fix extraction of symlinks
+Fix CVE-2014-8141: out-of-bounds read issues in getZip64Data()
+
 --- process.c.orig     Fri Mar  6 02:25:10 2009
-+++ process.c  Thu Jan  9 16:16:28 2014
++++ process.c  Thu Feb  5 18:57:59 2015
+@@ -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.
 @@ -1751,6 +1751,12 @@ int process_cdir_file_hdr(__G)    /* return PK-type er
          = (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11);
  #endif
@@ -14,3 +25,102 @@ $OpenBSD: patch-process_c,v 1.1 2014/01/
      return PK_COOL;
  
  } /* end function process_cdir_file_hdr() */
+@@ -1888,48 +1894,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);
+     }
-- 
Christian "naddy" Weisgerber                          na...@mips.inka.de

Reply via email to