Backport an upstream patch to fix erroneous "zip bomb" detection

ok naddy
This commit is contained in:
jcs 2020-11-14 17:45:17 +00:00
parent 248f18c28d
commit 68f39bf9dd
5 changed files with 104 additions and 35 deletions

View File

@ -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/

View File

@ -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;

View File

@ -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);

View File

@ -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 <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();

View File

@ -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;