unzip-zipbomb-switch.patch 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. From 5b44c818b96193b3e240f38f61985fa2bc780eb7 Mon Sep 17 00:00:00 2001
  2. From: Jakub Martisko <jamartis@redhat.com>
  3. Date: Tue, 30 Nov 2021 15:42:17 +0100
  4. Subject: [PATCH] Add an option to disable the zipbomb detection
  5. This can be done by settting a newly introduced environment variable
  6. UNZIP_DISABLE_ZIPBOMB_DETECTION to {TRUE,True,true}. If the variable is unset, or
  7. set to any other value the zipbomb detection is left enabled.
  8. Example:
  9. UNZIP_DISABLE_ZIPBOMB_DETECTION=True unzip ./zbsm.zip -d ./test
  10. ---
  11. extract.c | 85 ++++++++++++++++++++++++++++++-------------------------
  12. unzip.c | 15 ++++++++--
  13. unzip.h | 1 +
  14. 3 files changed, 60 insertions(+), 41 deletions(-)
  15. diff --git a/extract.c b/extract.c
  16. index 878817d..3e58071 100644
  17. --- a/extract.c
  18. +++ b/extract.c
  19. @@ -322,7 +322,8 @@ static ZCONST char Far BadExtraFieldCRC[] =
  20. static ZCONST char Far NotEnoughMemCover[] =
  21. "error: not enough memory for bomb detection\n";
  22. static ZCONST char Far OverlappedComponents[] =
  23. - "error: invalid zip file with overlapped components (possible zip bomb)\n";
  24. + "error: invalid zip file with overlapped components (possible zip bomb)\n \
  25. +To unzip the file anyway, rerun the command with UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE environmnent variable\n";
  26. @@ -502,35 +503,37 @@ int extract_or_test_files(__G) /* return PK-type error code */
  27. the end of central directory record (including the Zip64 end of central
  28. directory locator, if present), and the Zip64 end of central directory
  29. record, if present. */
  30. - if (G.cover == NULL) {
  31. + if (uO.zipbomb == TRUE) {
  32. + if (G.cover == NULL) {
  33. G.cover = malloc(sizeof(cover_t));
  34. if (G.cover == NULL) {
  35. - Info(slide, 0x401, ((char *)slide,
  36. - LoadFarString(NotEnoughMemCover)));
  37. - return PK_MEM;
  38. + Info(slide, 0x401, ((char *)slide,
  39. + LoadFarString(NotEnoughMemCover)));
  40. + return PK_MEM;
  41. }
  42. ((cover_t *)G.cover)->span = NULL;
  43. ((cover_t *)G.cover)->max = 0;
  44. - }
  45. - ((cover_t *)G.cover)->num = 0;
  46. - if (cover_add((cover_t *)G.cover,
  47. - G.extra_bytes + G.ecrec.offset_start_central_directory,
  48. - G.extra_bytes + G.ecrec.offset_start_central_directory +
  49. - G.ecrec.size_central_directory) != 0) {
  50. + }
  51. + ((cover_t *)G.cover)->num = 0;
  52. + if (cover_add((cover_t *)G.cover,
  53. + G.extra_bytes + G.ecrec.offset_start_central_directory,
  54. + G.extra_bytes + G.ecrec.offset_start_central_directory +
  55. + G.ecrec.size_central_directory) != 0) {
  56. Info(slide, 0x401, ((char *)slide,
  57. - LoadFarString(NotEnoughMemCover)));
  58. + LoadFarString(NotEnoughMemCover)));
  59. return PK_MEM;
  60. - }
  61. - if ((G.extra_bytes != 0 &&
  62. - cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
  63. - (G.ecrec.have_ecr64 &&
  64. - cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
  65. - G.ecrec.ec64_end) != 0) ||
  66. - cover_add((cover_t *)G.cover, G.ecrec.ec_start,
  67. - G.ecrec.ec_end) != 0) {
  68. + }
  69. + if ((G.extra_bytes != 0 &&
  70. + cover_add((cover_t *)G.cover, 0, G.extra_bytes) != 0) ||
  71. + (G.ecrec.have_ecr64 &&
  72. + cover_add((cover_t *)G.cover, G.ecrec.ec64_start,
  73. + G.ecrec.ec64_end) != 0) ||
  74. + cover_add((cover_t *)G.cover, G.ecrec.ec_start,
  75. + G.ecrec.ec_end) != 0) {
  76. Info(slide, 0x401, ((char *)slide,
  77. - LoadFarString(OverlappedComponents)));
  78. + LoadFarString(OverlappedComponents)));
  79. return PK_BOMB;
  80. + }
  81. }
  82. /*---------------------------------------------------------------------------
  83. @@ -1222,10 +1225,12 @@ static int extract_or_test_entrylist(__G__ numchunk,
  84. /* seek_zipf(__G__ pInfo->offset); */
  85. request = G.pInfo->offset + G.extra_bytes;
  86. - if (cover_within((cover_t *)G.cover, request)) {
  87. + if (uO.zipbomb == TRUE) {
  88. + if (cover_within((cover_t *)G.cover, request)) {
  89. Info(slide, 0x401, ((char *)slide,
  90. - LoadFarString(OverlappedComponents)));
  91. + LoadFarString(OverlappedComponents)));
  92. return PK_BOMB;
  93. + }
  94. }
  95. inbuf_offset = request % INBUFSIZ;
  96. bufstart = request - inbuf_offset;
  97. @@ -1758,17 +1763,19 @@ reprompt:
  98. return IZ_CTRLC; /* cancel operation by user request */
  99. }
  100. #endif
  101. - error = cover_add((cover_t *)G.cover, request,
  102. - G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
  103. - if (error < 0) {
  104. + if (uO.zipbomb == TRUE) {
  105. + error = cover_add((cover_t *)G.cover, request,
  106. + G.cur_zipfile_bufstart + (G.inptr - G.inbuf));
  107. + if (error < 0) {
  108. Info(slide, 0x401, ((char *)slide,
  109. - LoadFarString(NotEnoughMemCover)));
  110. + LoadFarString(NotEnoughMemCover)));
  111. return PK_MEM;
  112. - }
  113. - if (error != 0) {
  114. + }
  115. + if (error != 0) {
  116. Info(slide, 0x401, ((char *)slide,
  117. - LoadFarString(OverlappedComponents)));
  118. + LoadFarString(OverlappedComponents)));
  119. return PK_BOMB;
  120. + }
  121. }
  122. #ifdef MACOS /* MacOS is no preemptive OS, thus call event-handling by hand */
  123. UserStop();
  124. @@ -2171,8 +2178,8 @@ static int extract_or_test_member(__G) /* return PK-type error code */
  125. }
  126. undefer_input(__G);
  127. -
  128. - if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
  129. + if (uO.zipbomb == TRUE) {
  130. + if ((G.lrec.general_purpose_bit_flag & 8) != 0) {
  131. /* skip over data descriptor (harder than it sounds, due to signature
  132. * ambiguity)
  133. */
  134. @@ -2189,16 +2196,16 @@ static int extract_or_test_member(__G) /* return PK-type error code */
  135. ((G.lrec.csize & LOW) != SIG || /* if not SIG, have signature */
  136. (ulen == SIG && /* if not SIG, no signature */
  137. (G.pInfo->zip64 ? G.lrec.csize >> 32 : G.lrec.ucsize) != SIG
  138. - /* if not SIG, have signature */
  139. + /* if not SIG, have signature */
  140. )))))
  141. - /* skip four more bytes to account for signature */
  142. - shy += 4 - readbuf((char *)buf, 4);
  143. + /* skip four more bytes to account for signature */
  144. + shy += 4 - readbuf((char *)buf, 4);
  145. if (G.pInfo->zip64)
  146. - shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
  147. + shy += 8 - readbuf((char *)buf, 8); /* skip eight more for ZIP64 */
  148. if (shy)
  149. - error = PK_ERR;
  150. + error = PK_ERR;
  151. + }
  152. }
  153. -
  154. return error;
  155. } /* end function extract_or_test_member() */
  156. diff --git a/unzip.c b/unzip.c
  157. index 8dbfc95..abb3644 100644
  158. --- a/unzip.c
  159. +++ b/unzip.c
  160. @@ -1329,10 +1329,9 @@ int uz_opts(__G__ pargc, pargv)
  161. int *pargc;
  162. char ***pargv;
  163. {
  164. - char **argv, *s;
  165. + char **argv, *s, *zipbomb_envar;
  166. int argc, c, error=FALSE, negative=0, showhelp=0;
  167. -
  168. argc = *pargc;
  169. argv = *pargv;
  170. @@ -1923,6 +1922,18 @@ opts_done: /* yes, very ugly...but only used by UnZipSFX with -x xlist */
  171. else
  172. G.extract_flag = TRUE;
  173. + /* 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. */
  174. + zipbomb_envar = getenv("UNZIP_DISABLE_ZIPBOMB_DETECTION");
  175. + uO.zipbomb = TRUE;
  176. + if (zipbomb_envar != NULL) {
  177. + /* strcasecmp might be a better approach here but it is POSIX-only */
  178. + if ((strcmp ("TRUE", zipbomb_envar) == 0)
  179. + || (strcmp ("True", zipbomb_envar) == 0)
  180. + || (strcmp ("true",zipbomb_envar) == 0)) {
  181. + uO.zipbomb = FALSE;
  182. + }
  183. + }
  184. +
  185. *pargc = argc;
  186. *pargv = argv;
  187. return PK_OK;
  188. diff --git a/unzip.h b/unzip.h
  189. index ed24a5b..e7665e8 100644
  190. --- a/unzip.h
  191. +++ b/unzip.h
  192. @@ -559,6 +559,7 @@ typedef struct _UzpOpts {
  193. #ifdef UNIX
  194. int cflxflag; /* -^: allow control chars in extracted filenames */
  195. #endif
  196. + int zipbomb;
  197. #endif /* !FUNZIP */
  198. } UzpOpts;
  199. --
  200. 2.33.0