123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- From 5b44c818b96193b3e240f38f61985fa2bc780eb7 Mon Sep 17 00:00:00 2001
- From: Jakub Martisko <jamartis@redhat.com>
- Date: Tue, 30 Nov 2021 15:42:17 +0100
- Subject: [PATCH] Add an option to disable the zipbomb detection
- This can be done by settting a newly introduced environment variable
- UNZIP_DISABLE_ZIPBOMB_DETECTION to {TRUE,True,true}. If the variable is unset, or
- set to any other value the zipbomb detection is left enabled.
- Example:
- UNZIP_DISABLE_ZIPBOMB_DETECTION=True unzip ./zbsm.zip -d ./test
- ---
- extract.c | 85 ++++++++++++++++++++++++++++++-------------------------
- unzip.c | 15 ++++++++--
- unzip.h | 1 +
- 3 files changed, 60 insertions(+), 41 deletions(-)
- diff --git a/extract.c b/extract.c
- index 878817d..3e58071 100644
- --- a/extract.c
- +++ b/extract.c
- @@ -322,7 +322,8 @@ static ZCONST char Far BadExtraFieldCRC[] =
- 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";
- + "error: invalid zip file with overlapped components (possible zip bomb)\n \
- +To unzip the file anyway, rerun the command with UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE environmnent variable\n";
-
-
-
- @@ -502,35 +503,37 @@ int extract_or_test_files(__G) /* return PK-type error code */
- 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) {
- + if (uO.zipbomb == TRUE) {
- + if (G.cover == NULL) {
- G.cover = malloc(sizeof(cover_t));
- if (G.cover == NULL) {
- - Info(slide, 0x401, ((char *)slide,
- - LoadFarString(NotEnoughMemCover)));
- - return PK_MEM;
- + 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 (cover_add((cover_t *)G.cover,
- - G.extra_bytes + G.ecrec.offset_start_central_directory,
- - G.extra_bytes + G.ecrec.offset_start_central_directory +
- - G.ecrec.size_central_directory) != 0) {
- + }
- + ((cover_t *)G.cover)->num = 0;
- + if (cover_add((cover_t *)G.cover,
- + G.extra_bytes + G.ecrec.offset_start_central_directory,
- + G.extra_bytes + G.ecrec.offset_start_central_directory +
- + G.ecrec.size_central_directory) != 0) {
- Info(slide, 0x401, ((char *)slide,
- - LoadFarString(NotEnoughMemCover)));
- + 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) {
- + }
- + 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)));
- + LoadFarString(OverlappedComponents)));
- return PK_BOMB;
- + }
- }
-
- /*---------------------------------------------------------------------------
- @@ -1222,10 +1225,12 @@ 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)) {
- + if (uO.zipbomb == TRUE) {
- + if (cover_within((cover_t *)G.cover, request)) {
- Info(slide, 0x401, ((char *)slide,
- - LoadFarString(OverlappedComponents)));
- + LoadFarString(OverlappedComponents)));
- return PK_BOMB;
- + }
- }
- inbuf_offset = request % INBUFSIZ;
- bufstart = request - inbuf_offset;
- @@ -1758,17 +1763,19 @@ 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) {
- + if (uO.zipbomb == TRUE) {
- + 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)));
- + LoadFarString(NotEnoughMemCover)));
- return PK_MEM;
- - }
- - if (error != 0) {
- + }
- + if (error != 0) {
- Info(slide, 0x401, ((char *)slide,
- - LoadFarString(OverlappedComponents)));
- + LoadFarString(OverlappedComponents)));
- return PK_BOMB;
- + }
- }
- #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
- UserStop();
- @@ -2171,8 +2178,8 @@ static int extract_or_test_member(__G) /* return PK-type error code */
- }
-
- undefer_input(__G);
- -
- - if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
- + if (uO.zipbomb == TRUE) {
- + if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
- /* skip over data descriptor (harder than it sounds, due to signature
- * ambiguity)
- */
- @@ -2189,16 +2196,16 @@ static int extract_or_test_member(__G) /* return PK-type error code */
- ((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
- (ulen == SIG && /* if not SIG, no signature */
- (G.pInfo->zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
- - /* if not SIG, have signature */
- + /* if not SIG, have signature */
- )))))
- - /* skip four more bytes to account for signature */
- - shy += 4 - readbuf((char *)buf, 4);
- + /* skip four more bytes to account for signature */
- + shy += 4 - readbuf((char *)buf, 4);
- if (G.pInfo->zip64)
- - shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
- + shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
- if (shy)
- - error = PK_ERR;
- + error = PK_ERR;
- + }
- }
- -
- return error;
-
- } /* end function extract_or_test_member() */
- diff --git a/unzip.c b/unzip.c
- index 8dbfc95..abb3644 100644
- --- a/unzip.c
- +++ b/unzip.c
- @@ -1329,10 +1329,9 @@ int uz_opts(__G__ pargc, pargv)
- int *pargc;
- char ***pargv;
- {
- - char **argv, *s;
- + char **argv, *s, *zipbomb_envar;
- int argc, c, error=FALSE, negative=0, showhelp=0;
-
- -
- argc = *pargc;
- argv = *pargv;
-
- @@ -1923,6 +1922,18 @@ opts_done: /* yes, very ugly...but only used by UnZipSFX with -x xlist */
- else
- G.extract_flag = TRUE;
-
- + /* Disable the zipbomb detection, this is the only option set only via the shell variables but it should at least not clash with something in the future. */
- + zipbomb_envar = getenv("UNZIP_DISABLE_ZIPBOMB_DETECTION");
- + uO.zipbomb = TRUE;
- + if (zipbomb_envar != NULL) {
- + /* strcasecmp might be a better approach here but it is POSIX-only */
- + if ((strcmp ("TRUE", zipbomb_envar) == 0)
- + || (strcmp ("True", zipbomb_envar) == 0)
- + || (strcmp ("true",zipbomb_envar) == 0)) {
- + uO.zipbomb = FALSE;
- + }
- + }
- +
- *pargc = argc;
- *pargv = argv;
- return PK_OK;
- diff --git a/unzip.h b/unzip.h
- index ed24a5b..e7665e8 100644
- --- a/unzip.h
- +++ b/unzip.h
- @@ -559,6 +559,7 @@ typedef struct _UzpOpts {
- #ifdef UNIX
- int cflxflag; /* -^: allow control chars in extracted filenames */
- #endif
- + int zipbomb;
- #endif /* !FUNZIP */
- } UzpOpts;
-
- --
- 2.33.0
|