You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
7.3 KiB
200 lines
7.3 KiB
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,6 +2196,7 @@ static int extract_or_test_member(__G) /* return PK-type error code */ |
|
shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */ |
|
if (shy) |
|
error = PK_ERR; |
|
+ } |
|
} |
|
|
|
return error; |
|
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 |
|
|
|
|