From 5b44c818b96193b3e240f38f61985fa2bc780eb7 Mon Sep 17 00:00:00 2001 From: Jakub Martisko 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