Hi ports@, the archivers/unzip port has two unfixed CVE: CVE-2019-13232 and CVE-2018-1000035 Additionaly the bug bluhm@ patched in 2017 got a name too CVE-2018-18384
The diff is attached, further info is included with the patches. mbuhl Index: archivers/unzip/Makefile =================================================================== RCS file: /cvs/ports/archivers/unzip/Makefile,v retrieving revision 1.64 diff -u -p -r1.64 Makefile --- archivers/unzip/Makefile 12 Jul 2019 20:43:30 -0000 1.64 +++ archivers/unzip/Makefile 20 Feb 2020 07:20:15 -0000 @@ -7,7 +7,7 @@ COMMENT = extract, list & test files in VERSION = 6.0 DISTNAME = unzip${VERSION:S/.//} PKGNAME = unzip-${VERSION} -REVISION = 12 +REVISION = 13 CATEGORIES = archivers MASTER_SITES = ${MASTER_SITE_SOURCEFORGE:=infozip/} \ ftp://ftp.info-zip.org/pub/infozip/src/ Index: archivers/unzip/patches/patch-extract_c =================================================================== RCS file: /cvs/ports/archivers/unzip/patches/patch-extract_c,v retrieving revision 1.2 diff -u -p -r1.2 patch-extract_c --- archivers/unzip/patches/patch-extract_c 23 Mar 2017 17:26:17 -0000 1.2 +++ archivers/unzip/patches/patch-extract_c 20 Feb 2020 08:49:05 -0000 @@ -12,6 +12,8 @@ Fix CVE-2015-7697: infinite loop when ex https://bugs.debian.org/802160 https://bugzilla.redhat.com/show_bug.cgi?id=1260944 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 --- extract.c.orig Sat Mar 14 02:32:52 2009 +++ extract.c Tue Mar 21 16:10:27 2017 @@ -31,6 +33,189 @@ Fix CVE-2015-7697: infinite loop when ex static ZCONST char Far InvalidComprDataEAs[] = " invalid compressed data for EAs\n"; # if (defined(WIN32) && defined(NTSD_EAS)) +@@ -321,11 +321,130 @@ 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; ++} ++ ++ ++ ++ ++ + /**************************************/ + /* Function extract_or_test_files() */ + /**************************************/ +@@ -376,6 +495,29 @@ 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. */ ++ 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 +@@ -593,7 +735,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) */ +- 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 */ +@@ -1062,6 +1205,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; + @@ -1255,8 +1257,17 @@ static int extract_or_test_entrylist(__G__ numchunk, if (G.lrec.compression_method == STORED) { zusz_t csiz_decrypted = G.lrec.csize; @@ -50,6 +235,60 @@ Fix CVE-2015-7697: infinite loop when ex if (G.lrec.ucsize != csiz_decrypted) { Info(slide, 0x401, ((char *)slide, LoadFarStringSmall2(WrnStorUCSizCSizDiff), +@@ -1602,6 +1750,18 @@ 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) { ++ 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 +@@ -2003,6 +2163,34 @@ static int extract_or_test_member(__G) /* return PK + } + + 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() */ @@ -2023,7 +2034,8 @@ static int TestExtraField(__G__ ef, ef_len) ebID = makeword(ef); ebLen = (unsigned)makeword(ef+EB_LEN); Index: archivers/unzip/patches/patch-fileio_c =================================================================== RCS file: /cvs/ports/archivers/unzip/patches/patch-fileio_c,v retrieving revision 1.1 diff -u -p -r1.1 patch-fileio_c --- archivers/unzip/patches/patch-fileio_c 6 Feb 2015 21:37:04 -0000 1.1 +++ archivers/unzip/patches/patch-fileio_c 20 Feb 2020 08:06:53 -0000 @@ -1,6 +1,10 @@ $OpenBSD: patch-fileio_c,v 1.1 2015/02/06 21:37:04 naddy Exp $ Fix CVE-2014-8141: out-of-bounds read issues in getZip64Data() +Fix CVE-2018-1000035: buffer overflow for password-protected archives +https://security-tracker.debian.org/tracker/CVE-2018-1000035 +Fix CVE-2019-13232: a zip bomb using overlapped entries +https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c --- fileio.c.orig Mon Apr 20 02:03:44 2009 +++ fileio.c Thu Feb 5 18:57:59 2015 @@ -13,6 +17,48 @@ Fix CVE-2014-8141: out-of-bounds read is #ifdef WINDLL static ZCONST char Far DiskFullQuery[] = +@@ -532,8 +532,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; +@@ -1613,7 +1613,11 @@ int UZ_EXP UzpPassword (pG, rcnt, pwbuf, + int r = IZ_PW_ENTERED; + char *m; + char *prompt; +- ++ char *zfnf; ++ char *efnf; ++ size_t zfnfl; ++ int isOverflow; ++ + #ifndef REENTRANT + /* tell picky compilers to shut up about "unused variable" warnings */ + pG = pG; +@@ -1621,7 +1625,15 @@ int UZ_EXP UzpPassword (pG, rcnt, pwbuf, + + if (*rcnt == 0) { /* First call for current entry */ + *rcnt = 2; +- if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) { ++ zfnf = FnFilter1(zfn); ++ efnf = FnFilter2(efn); ++ zfnfl = strlen(zfnf); ++ isOverflow = TRUE; ++ if (2*FILNAMSIZ >= zfnfl && (2*FILNAMSIZ - zfnfl) >= strlen(efnf)) ++ { ++ isOverflow = FALSE; ++ } ++ if ((isOverflow == FALSE) && ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL)) { + sprintf(prompt, LoadFarString(PasswPrompt), + FnFilter1(zfn), FnFilter2(efn)); + m = prompt; @@ -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; Index: archivers/unzip/patches/patch-globals_c =================================================================== RCS file: archivers/unzip/patches/patch-globals_c diff -N archivers/unzip/patches/patch-globals_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ archivers/unzip/patches/patch-globals_c 20 Feb 2020 08:50:28 -0000 @@ -0,0 +1,15 @@ +$OpenBSD$ + +Fix CVE-2019-13232: a zip bomb using overlapped entries +https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c + +--- globals.c.orig ++++ 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); Index: archivers/unzip/patches/patch-globals_h =================================================================== RCS file: archivers/unzip/patches/patch-globals_h diff -N archivers/unzip/patches/patch-globals_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ archivers/unzip/patches/patch-globals_h 20 Feb 2020 08:50:48 -0000 @@ -0,0 +1,23 @@ +$OpenBSD$ + +Fix CVE-2019-13232: a zip bomb using overlapped entries +https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c + +--- glabals.h.orig ++++ 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 */ Index: archivers/unzip/patches/patch-list_c =================================================================== RCS file: /cvs/ports/archivers/unzip/patches/patch-list_c,v retrieving revision 1.1 diff -u -p -r1.1 patch-list_c --- archivers/unzip/patches/patch-list_c 23 Mar 2017 17:26:17 -0000 1.1 +++ archivers/unzip/patches/patch-list_c 20 Feb 2020 07:41:50 -0000 @@ -1,14 +1,16 @@ $OpenBSD: patch-list_c,v 1.1 2017/03/23 17:26:17 bluhm Exp $ -Fix: increase size of cfactorstr array to avoid buffer overflow +Fix CVE-2018-18384: increase size of cfactorstr array to avoid buffer overflow https://bugs.debian.org/741384 + https://sourceforge.net/p/infozip/bugs/53/ Fix CVE-2014-9913: buffer overflow in unzip https://sourceforge.net/p/infozip/bugs/27/ https://bugs.debian.org/847485 https://launchpad.net/bugs/387350 ---- list.c.orig Sun Feb 8 18:11:34 2009 -+++ list.c Tue Mar 21 16:10:27 2017 +Index: list.c +--- list.c.orig ++++ 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; @@ -38,3 +40,27 @@ Fix CVE-2014-9913: buffer overflow in un } #if 0 /* GRR/Euro: add this? */ +@@ -378,9 +389,9 @@ int list_files(__G) /* return PK-type error code */ + } + #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, +@@ -460,9 +471,9 @@ int list_files(__G) /* return PK-type error code */ + + #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"), Index: archivers/unzip/patches/patch-process_c =================================================================== RCS file: /cvs/ports/archivers/unzip/patches/patch-process_c,v retrieving revision 1.3 diff -u -p -r1.3 patch-process_c --- archivers/unzip/patches/patch-process_c 23 Mar 2017 17:26:17 -0000 1.3 +++ archivers/unzip/patches/patch-process_c 20 Feb 2020 08:48:45 -0000 @@ -8,6 +8,8 @@ Fix: do not ignore extra fields containi https://bugs.debian.org/842993 Fix: restore uid and gid information when requested https://bugs.debian.org/689212 +Fix CVE-2019-13232: a zip bomb using overlapped entries +https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c --- process.c.orig Fri Mar 6 02:25:10 2009 +++ process.c Tue Mar 21 16:10:27 2017 Index: archivers/unzip/patches/patch-unzip_h =================================================================== RCS file: archivers/unzip/patches/patch-unzip_h diff -N archivers/unzip/patches/patch-unzip_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ archivers/unzip/patches/patch-unzip_h 20 Feb 2020 08:56:01 -0000 @@ -0,0 +1,14 @@ +$OpenBSD$ + +Fix CVE-2019-13232: a zip bomb using overlapped entries +https://github.com/madler/unzip/commit/47b3ceae397d21bf822bc2ac73052a4b1daf8e1c + +--- unzip.h.orig ++++ 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 */