As noted in the comments of the GitHub commit referenced in the
existing patches:

https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c

There is another commit needed that fixes erroneous "bomb" detection 
on legitimate zip files, like one that I'm trying to work with for a 
port distfile.

https://github.com/madler/unzip/commit/6d351831be705cc26d897db44f878a978f4138fc


Index: Makefile
===================================================================
RCS file: /cvs/ports/archivers/unzip/Makefile,v
retrieving revision 1.65
diff -u -p -u -p -r1.65 Makefile
--- Makefile    11 Mar 2020 21:57:31 -0000      1.65
+++ Makefile    12 Nov 2020 18:01:37 -0000
@@ -7,7 +7,7 @@ COMMENT =       extract, list & test files in 
 VERSION =      6.0
 DISTNAME =     unzip${VERSION:S/.//}
 PKGNAME =      unzip-${VERSION}
-REVISION =     13
+REVISION =     14
 CATEGORIES =   archivers
 MASTER_SITES = ${MASTER_SITE_SOURCEFORGE:=infozip/} \
                ftp://ftp.info-zip.org/pub/infozip/src/
Index: patches/patch-extract_c
===================================================================
RCS file: /cvs/ports/archivers/unzip/patches/patch-extract_c,v
retrieving revision 1.3
diff -u -p -u -p -r1.3 patch-extract_c
--- patches/patch-extract_c     11 Mar 2020 21:57:32 -0000      1.3
+++ patches/patch-extract_c     12 Nov 2020 18:01:37 -0000
@@ -14,6 +14,7 @@ Fix CVE-2015-7697: infinite loop when ex
     https://bugzilla.redhat.com/attachment.cgi?id=1073339
 Fix CVE-2019-13232: a zip bomb using overlapped entries
 https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c
+https://github.com/madler/unzip/commit/6d351831be705cc26d897db44f878a978f4138fc
 
 Index: extract.c
 --- extract.c.orig
@@ -165,12 +166,15 @@ Index: extract.c
  /**************************************/
  /*  Function extract_or_test_files()  */
  /**************************************/
-@@ -374,6 +495,29 @@ int extract_or_test_files(__G)    /* return PK-type er
+@@ -374,6 +495,42 @@ int extract_or_test_files(__G)    /* return PK-type er
      }
  #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) {
@@ -182,20 +186,30 @@ Index: extract.c
 +        ((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-
      rectory lies at the end of the zipfile and the member files lie at the
-@@ -591,7 +735,8 @@ int extract_or_test_files(__G)    /* return PK-type er
+@@ -591,7 +748,8 @@ int extract_or_test_files(__G)    /* return PK-type er
              if (error > error_in_archive)
                  error_in_archive = error;
              /* ...and keep going (unless disk full or user break) */
@@ -205,7 +219,7 @@ Index: extract.c
                  /* clear reached_end to signal premature stop ... */
                  reached_end = FALSE;
                  /* ... and cancel scanning the central directory */
-@@ -1060,6 +1205,11 @@ static int extract_or_test_entrylist(__G__ numchunk,
+@@ -1060,6 +1218,11 @@ static int extract_or_test_entrylist(__G__ numchunk,
  
          /* seek_zipf(__G__ pInfo->offset);  */
          request = G.pInfo->offset + G.extra_bytes;
@@ -217,7 +231,7 @@ Index: extract.c
          inbuf_offset = request % INBUFSIZ;
          bufstart = request - inbuf_offset;
  
-@@ -1255,8 +1405,17 @@ static int extract_or_test_entrylist(__G__ numchunk,
+@@ -1255,8 +1418,17 @@ static int extract_or_test_entrylist(__G__ numchunk,
          if (G.lrec.compression_method == STORED) {
              zusz_t csiz_decrypted = G.lrec.csize;
  
@@ -236,7 +250,7 @@ Index: extract.c
              if (G.lrec.ucsize != csiz_decrypted) {
                  Info(slide, 0x401, ((char *)slide,
                    LoadFarStringSmall2(WrnStorUCSizCSizDiff),
-@@ -1591,6 +1750,18 @@ reprompt:
+@@ -1591,6 +1763,18 @@ reprompt:
              return IZ_CTRLC;        /* cancel operation by user request */
          }
  #endif
@@ -255,7 +269,7 @@ Index: extract.c
  #ifdef MACOS  /* MacOS is no preemptive OS, thus call event-handling by hand 
*/
          UserStop();
  #endif
-@@ -1992,6 +2163,34 @@ static int extract_or_test_member(__G)    /* return PK
+@@ -1992,6 +2176,34 @@ static int extract_or_test_member(__G)    /* return PK
      }
  
      undefer_input(__G);
@@ -290,7 +304,7 @@ Index: extract.c
      return error;
  
  } /* end function extract_or_test_member() */
-@@ -2023,7 +2222,8 @@ static int TestExtraField(__G__ ef, ef_len)
+@@ -2023,7 +2235,8 @@ static int TestExtraField(__G__ ef, ef_len)
          ebID = makeword(ef);
          ebLen = (unsigned)makeword(ef+EB_LEN);
  
@@ -300,7 +314,7 @@ Index: extract.c
             /* Discovered some extra field inconsistency! */
              if (uO.qflag)
                  Info(slide, 1, ((char *)slide, "%-22s ",
-@@ -2158,11 +2358,19 @@ static int TestExtraField(__G__ ef, ef_len)
+@@ -2158,11 +2371,19 @@ static int TestExtraField(__G__ ef, ef_len)
                  }
                  break;
              case EF_PKVMS:
@@ -321,7 +335,7 @@ Index: extract.c
                  break;
              case EF_PKW32:
              case EF_PKUNIX:
-@@ -2217,15 +2425,32 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offs
+@@ -2217,15 +2438,32 @@ static int test_compr_eb(__G__ eb, eb_size, compr_offs
      ulg eb_ucsize;
      uch *eb_ucptr;
      int r;
@@ -357,7 +371,7 @@ Index: extract.c
      if (
  #ifdef INT_16BIT
          (((ulg)(extent)eb_ucsize) != eb_ucsize) ||
-@@ -2700,6 +2925,12 @@ __GDEF
+@@ -2700,6 +2938,12 @@ __GDEF
      int err=BZ_OK;
      int repeated_buf_err;
      bz_stream bstrm;
Index: patches/patch-process_c
===================================================================
RCS file: /cvs/ports/archivers/unzip/patches/patch-process_c,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 patch-process_c
--- patches/patch-process_c     11 Mar 2020 21:57:32 -0000      1.4
+++ patches/patch-process_c     12 Nov 2020 18:01:37 -0000
@@ -10,6 +10,7 @@ Fix: restore uid and gid information whe
     https://bugs.debian.org/689212
 Fix CVE-2019-13232: a zip bomb using overlapped entries
 https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c
+https://github.com/madler/unzip/commit/6d351831be705cc26d897db44f878a978f4138fc
 
 Index: process.c
 --- process.c.orig
@@ -35,7 +36,27 @@ Index: process.c
  } /* end function free_G_buffers() */
  
  
-@@ -1729,6 +1736,13 @@ int process_cdir_file_hdr(__G)    /* return PK-type er
+@@ -1401,6 +1408,10 @@ static int find_ecrec64(__G__ searchlen)         /* re
+ 
+     /* 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;
+@@ -1535,6 +1546,8 @@ static int find_ecrec(__G__ searchlen)          /* ret
+       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.
+@@ -1729,6 +1742,13 @@ int process_cdir_file_hdr(__G)    /* return PK-type er
      else if (uO.L_flag > 1)   /* let -LL force lower case for all names */
          G.pInfo->lcflag = 1;
  
@@ -49,7 +70,7 @@ Index: process.c
      /* do Amigas (AMIGA_) also have volume labels? */
      if (IS_VOLID(G.crec.external_file_attributes) &&
          (G.pInfo->hostnum == FS_FAT_ || G.pInfo->hostnum == FS_HPFS_ ||
-@@ -1751,6 +1765,12 @@ int process_cdir_file_hdr(__G)    /* return PK-type er
+@@ -1751,6 +1771,12 @@ int process_cdir_file_hdr(__G)    /* return PK-type er
          = (G.crec.general_purpose_bit_flag & (1 << 11)) == (1 << 11);
  #endif
  
@@ -62,7 +83,7 @@ Index: process.c
      return PK_COOL;
  
  } /* end function process_cdir_file_hdr() */
-@@ -1888,48 +1908,84 @@ int getZip64Data(__G__ ef_buf, ef_len)
+@@ -1888,48 +1914,84 @@ 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.
@@ -163,7 +184,7 @@ Index: process.c
          ef_buf += (eb_len + EB_HEADSIZE);
          ef_len -= (eb_len + EB_HEADSIZE);
      }
-@@ -2037,6 +2093,8 @@ int getUnicodeData(__G__ ef_buf, ef_len)
+@@ -2037,6 +2099,8 @@ int getUnicodeData(__G__ ef_buf, ef_len)
                      (ZCONST char *)(offset + ef_buf), ULen);
              G.unipath_filename[ULen] = '\0';
            }
@@ -172,7 +193,7 @@ Index: process.c
          }
  
          /* Skip this extra field block */
-@@ -2867,10 +2925,13 @@ unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos
+@@ -2867,10 +2931,13 @@ unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos
              break;
  
            case EF_IZUNIX2:
@@ -188,7 +209,7 @@ Index: process.c
  #ifdef IZ_HAVE_UXUIDGID
              if (have_new_type_eb > 1)
                  break;          /* IZUNIX3 overrides IZUNIX2 e.f. block ! */
-@@ -2886,6 +2947,8 @@ unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos
+@@ -2886,6 +2953,8 @@ unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos
              /* new 3rd generation Unix ef */
              have_new_type_eb = 2;
  
@@ -197,7 +218,7 @@ Index: process.c
          /*
            Version       1 byte      version of this extra field, currently 1
            UIDSize       1 byte      Size of UID field
-@@ -2897,7 +2960,7 @@ unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos
+@@ -2897,7 +2966,7 @@ unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos
  #ifdef IZ_HAVE_UXUIDGID
              if (eb_len >= EB_UX3_MINLEN
                  && z_uidgid != NULL
@@ -206,7 +227,7 @@ Index: process.c
                      /* only know about version 1 */
              {
                  uch uid_size;
-@@ -2906,13 +2969,11 @@ unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos
+@@ -2906,13 +2975,11 @@ unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos
                  uid_size = *((EB_HEADSIZE + 1) + ef_buf);
                  gid_size = *((EB_HEADSIZE + uid_size + 2) + ef_buf);
  
Index: patches/patch-unzip_c
===================================================================
RCS file: /cvs/ports/archivers/unzip/patches/patch-unzip_c,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 patch-unzip_c
--- patches/patch-unzip_c       20 Oct 2015 13:13:52 -0000      1.2
+++ patches/patch-unzip_c       12 Nov 2020 18:01:37 -0000
@@ -1,13 +1,22 @@
 $OpenBSD: patch-unzip_c,v 1.2 2015/10/20 13:13:52 ajacoutot Exp $
---- unzip.c.orig       Wed Oct  7 12:11:04 2015
-+++ unzip.c    Wed Oct  7 12:12:09 2015
-@@ -717,6 +717,9 @@ int MAIN(argc, argv)   /* return PK-type error code (e
+Index: unzip.c
+--- unzip.c.orig
++++ unzip.c
+@@ -65,6 +65,7 @@
+ 
+ #define __UNZIP_C       /* identifies this source module */
+ #define UNZIP_INTERNAL
++#include <err.h>
+ #include "unzip.h"      /* includes, typedefs, macros, prototypes, etc. */
+ #include "crypt.h"
+ #include "unzvers.h"
+@@ -716,6 +717,9 @@ int MAIN(argc, argv)   /* return PK-type error code (e
+     char *argv[];
  {
      int r;
- 
++
 +    if (pledge("stdio rpath wpath cpath fattr tty", NULL) == -1)
 +        err(1, "pledge");
-+
+ 
      CONSTRUCTGLOBALS();
      r = unzip(__G__ argc, argv);
-     DESTROYGLOBALS();
Index: patches/patch-unzpriv_h
===================================================================
RCS file: patches/patch-unzpriv_h
diff -N patches/patch-unzpriv_h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-unzpriv_h     12 Nov 2020 18:01:37 -0000
@@ -0,0 +1,25 @@
+$OpenBSD$
+
+Fix CVE-2019-13232: a zip bomb using overlapped entries
+https://github.com/madler/unzip/commit/6d351831be705cc26d897db44f878a978f4138fc
+
+Index: unzpriv.h
+--- unzpriv.h.orig
++++ 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;
+ 
+ 

Reply via email to