diff --git a/archivers/unzip/Makefile b/archivers/unzip/Makefile index fa770028fe9..ca98f1049dd 100644 --- a/archivers/unzip/Makefile +++ b/archivers/unzip/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.65 2020/03/11 21:57:31 naddy Exp $ +# $OpenBSD: Makefile,v 1.66 2020/11/14 17:45:17 jcs Exp $ PORTROACH = skipv:551,552 @@ -7,7 +7,7 @@ COMMENT = extract, list & test files in a ZIP archive 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/ diff --git a/archivers/unzip/patches/patch-extract_c b/archivers/unzip/patches/patch-extract_c index 8f25f9cf787..34ef7c7c0ec 100644 --- a/archivers/unzip/patches/patch-extract_c +++ b/archivers/unzip/patches/patch-extract_c @@ -1,4 +1,4 @@ -$OpenBSD: patch-extract_c,v 1.3 2020/03/11 21:57:32 naddy Exp $ +$OpenBSD: patch-extract_c,v 1.4 2020/11/14 17:45:17 jcs Exp $ Fix CVE-2015-7696: prevent unsigned overflow on invalid input https://bugzilla.redhat.com/attachment.cgi?id=1075942 @@ -14,6 +14,7 @@ Fix CVE-2015-7697: infinite loop when extracting empty bzip2 data 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; diff --git a/archivers/unzip/patches/patch-process_c b/archivers/unzip/patches/patch-process_c index c66f8c122f3..c289bb15f7c 100644 --- a/archivers/unzip/patches/patch-process_c +++ b/archivers/unzip/patches/patch-process_c @@ -1,4 +1,4 @@ -$OpenBSD: patch-process_c,v 1.4 2020/03/11 21:57:32 naddy Exp $ +$OpenBSD: patch-process_c,v 1.5 2020/11/14 17:45:17 jcs Exp $ Fix: handle the PKWare verification bit of internal attributes https://bugs.debian.org/630078 @@ -10,6 +10,7 @@ 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 +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); diff --git a/archivers/unzip/patches/patch-unzip_c b/archivers/unzip/patches/patch-unzip_c index 7d4e9918d20..feb210ac653 100644 --- a/archivers/unzip/patches/patch-unzip_c +++ b/archivers/unzip/patches/patch-unzip_c @@ -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 +$OpenBSD: patch-unzip_c,v 1.3 2020/11/14 17:45:17 jcs Exp $ +Index: unzip.c +--- unzip.c.orig ++++ unzip.c +@@ -65,6 +65,7 @@ + + #define __UNZIP_C /* identifies this source module */ + #define UNZIP_INTERNAL ++#include + #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(); diff --git a/archivers/unzip/patches/patch-unzpriv_h b/archivers/unzip/patches/patch-unzpriv_h new file mode 100644 index 00000000000..d5b75d58843 --- /dev/null +++ b/archivers/unzip/patches/patch-unzpriv_h @@ -0,0 +1,25 @@ +$OpenBSD: patch-unzpriv_h,v 1.1 2020/11/14 17:45:17 jcs Exp $ + +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; + +