aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-08 20:02:01 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-08 20:05:04 +0200
commit38ccd6af8abbafff98d458a1c62909acfc09a514 (patch)
tree1a4158db5c7e5e98111ff99d4a9078d93b4ccfcc
parent8e2174e9bd836e53c8b9c6e00d1bc6e2a718686e (diff)
downloadbusybox-w32-38ccd6af8abbafff98d458a1c62909acfc09a514.tar.gz
busybox-w32-38ccd6af8abbafff98d458a1c62909acfc09a514.tar.bz2
busybox-w32-38ccd6af8abbafff98d458a1c62909acfc09a514.zip
bzip2: fix two crashes on corrupted archives
As it turns out, longjmp'ing into freed stack is not healthy... function old new delta unpack_usage_messages - 97 +97 unpack_bz2_stream 369 409 +40 get_next_block 1667 1677 +10 get_bits 156 155 -1 start_bunzip 212 183 -29 bb_show_usage 181 120 -61 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/3 up/down: 147/-91) Total: 56 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--archival/libarchive/decompress_bunzip2.c78
-rw-r--r--archival/libarchive/decompress_gunzip.c1
-rw-r--r--coreutils/test.c1
-rw-r--r--include/bb_archive.h2
-rw-r--r--libbb/appletlib.c17
-rw-r--r--miscutils/bbconfig.c19
-rw-r--r--shell/ash.c1
-rwxr-xr-xtestsuite/bunzip2.tests16
-rw-r--r--testsuite/bz2_issue_11.bz2bin0 -> 12000 bytes
-rw-r--r--testsuite/bz2_issue_12.bz2bin0 -> 11000 bytes
10 files changed, 99 insertions, 36 deletions
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index bec89edd3..7ef4e035f 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -100,7 +100,7 @@ struct bunzip_data {
100 unsigned dbufSize; 100 unsigned dbufSize;
101 101
102 /* For I/O error handling */ 102 /* For I/O error handling */
103 jmp_buf jmpbuf; 103 jmp_buf *jmpbuf;
104 104
105 /* Big things go last (register-relative addressing can be larger for big offsets) */ 105 /* Big things go last (register-relative addressing can be larger for big offsets) */
106 uint32_t crc32Table[256]; 106 uint32_t crc32Table[256];
@@ -127,7 +127,7 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted)
127 /* if "no input fd" case: in_fd == -1, read fails, we jump */ 127 /* if "no input fd" case: in_fd == -1, read fails, we jump */
128 bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE); 128 bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE);
129 if (bd->inbufCount <= 0) 129 if (bd->inbufCount <= 0)
130 longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF); 130 longjmp(*bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF);
131 bd->inbufPos = 0; 131 bd->inbufPos = 0;
132 } 132 }
133 133
@@ -151,12 +151,12 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted)
151 151
152 return bits; 152 return bits;
153} 153}
154//#define get_bits(bd, n) (dbg("%d:get_bits()", __LINE__), get_bits(bd, n))
154 155
155/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */ 156/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */
156static int get_next_block(bunzip_data *bd) 157static int get_next_block(bunzip_data *bd)
157{ 158{
158 struct group_data *hufGroup; 159 int groupCount, selector,
159 int groupCount, *base, *limit, selector,
160 i, j, symCount, symTotal, nSelectors, byteCount[256]; 160 i, j, symCount, symTotal, nSelectors, byteCount[256];
161 uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; 161 uint8_t uc, symToByte[256], mtfSymbol[256], *selectors;
162 uint32_t *dbuf; 162 uint32_t *dbuf;
@@ -179,15 +179,19 @@ static int get_next_block(bunzip_data *bd)
179 i = get_bits(bd, 24); 179 i = get_bits(bd, 24);
180 j = get_bits(bd, 24); 180 j = get_bits(bd, 24);
181 bd->headerCRC = get_bits(bd, 32); 181 bd->headerCRC = get_bits(bd, 32);
182 if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK; 182 if ((i == 0x177245) && (j == 0x385090))
183 if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA; 183 return RETVAL_LAST_BLOCK;
184 if ((i != 0x314159) || (j != 0x265359))
185 return RETVAL_NOT_BZIP_DATA;
184 186
185 /* We can add support for blockRandomised if anybody complains. There was 187 /* We can add support for blockRandomised if anybody complains. There was
186 some code for this in busybox 1.0.0-pre3, but nobody ever noticed that 188 some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
187 it didn't actually work. */ 189 it didn't actually work. */
188 if (get_bits(bd, 1)) return RETVAL_OBSOLETE_INPUT; 190 if (get_bits(bd, 1))
191 return RETVAL_OBSOLETE_INPUT;
189 origPtr = get_bits(bd, 24); 192 origPtr = get_bits(bd, 24);
190 if (origPtr > bd->dbufSize) return RETVAL_DATA_ERROR; 193 if (origPtr > bd->dbufSize)
194 return RETVAL_DATA_ERROR;
191 195
192 /* mapping table: if some byte values are never used (encoding things 196 /* mapping table: if some byte values are never used (encoding things
193 like ascii text), the compression code removes the gaps to have fewer 197 like ascii text), the compression code removes the gaps to have fewer
@@ -231,13 +235,21 @@ static int get_next_block(bunzip_data *bd)
231 /* Get next value */ 235 /* Get next value */
232 int n = 0; 236 int n = 0;
233 while (get_bits(bd, 1)) { 237 while (get_bits(bd, 1)) {
234 if (n >= groupCount) return RETVAL_DATA_ERROR; 238 if (n >= groupCount)
239 return RETVAL_DATA_ERROR;
235 n++; 240 n++;
236 } 241 }
237 /* Decode MTF to get the next selector */ 242 /* Decode MTF to get the next selector */
238 tmp_byte = mtfSymbol[n]; 243 tmp_byte = mtfSymbol[n];
239 while (--n >= 0) 244 while (--n >= 0)
240 mtfSymbol[n + 1] = mtfSymbol[n]; 245 mtfSymbol[n + 1] = mtfSymbol[n];
246//We catch it later, in the second loop where we use selectors[i].
247//Maybe this is a better place, though?
248// if (tmp_byte >= groupCount) {
249// dbg("%d: selectors[%d]:%d groupCount:%d",
250// __LINE__, i, tmp_byte, groupCount);
251// return RETVAL_DATA_ERROR;
252// }
241 mtfSymbol[0] = selectors[i] = tmp_byte; 253 mtfSymbol[0] = selectors[i] = tmp_byte;
242 } 254 }
243 255
@@ -248,6 +260,8 @@ static int get_next_block(bunzip_data *bd)
248 uint8_t length[MAX_SYMBOLS]; 260 uint8_t length[MAX_SYMBOLS];
249 /* 8 bits is ALMOST enough for temp[], see below */ 261 /* 8 bits is ALMOST enough for temp[], see below */
250 unsigned temp[MAX_HUFCODE_BITS+1]; 262 unsigned temp[MAX_HUFCODE_BITS+1];
263 struct group_data *hufGroup;
264 int *base, *limit;
251 int minLen, maxLen, pp, len_m1; 265 int minLen, maxLen, pp, len_m1;
252 266
253 /* Read Huffman code lengths for each symbol. They're stored in 267 /* Read Huffman code lengths for each symbol. They're stored in
@@ -283,8 +297,10 @@ static int get_next_block(bunzip_data *bd)
283 /* Find largest and smallest lengths in this group */ 297 /* Find largest and smallest lengths in this group */
284 minLen = maxLen = length[0]; 298 minLen = maxLen = length[0];
285 for (i = 1; i < symCount; i++) { 299 for (i = 1; i < symCount; i++) {
286 if (length[i] > maxLen) maxLen = length[i]; 300 if (length[i] > maxLen)
287 else if (length[i] < minLen) minLen = length[i]; 301 maxLen = length[i];
302 else if (length[i] < minLen)
303 minLen = length[i];
288 } 304 }
289 305
290 /* Calculate permute[], base[], and limit[] tables from length[]. 306 /* Calculate permute[], base[], and limit[] tables from length[].
@@ -320,7 +336,8 @@ static int get_next_block(bunzip_data *bd)
320 /* Count symbols coded for at each bit length */ 336 /* Count symbols coded for at each bit length */
321 /* NB: in pathological cases, temp[8] can end ip being 256. 337 /* NB: in pathological cases, temp[8] can end ip being 256.
322 * That's why uint8_t is too small for temp[]. */ 338 * That's why uint8_t is too small for temp[]. */
323 for (i = 0; i < symCount; i++) temp[length[i]]++; 339 for (i = 0; i < symCount; i++)
340 temp[length[i]]++;
324 341
325 /* Calculate limit[] (the largest symbol-coding value at each bit 342 /* Calculate limit[] (the largest symbol-coding value at each bit
326 * length, which is (previous limit<<1)+symbols at this level), and 343 * length, which is (previous limit<<1)+symbols at this level), and
@@ -363,12 +380,22 @@ static int get_next_block(bunzip_data *bd)
363 380
364 runPos = dbufCount = selector = 0; 381 runPos = dbufCount = selector = 0;
365 for (;;) { 382 for (;;) {
383 struct group_data *hufGroup;
384 int *base, *limit;
366 int nextSym; 385 int nextSym;
386 uint8_t ngrp;
367 387
368 /* Fetch next Huffman coding group from list. */ 388 /* Fetch next Huffman coding group from list. */
369 symCount = GROUP_SIZE - 1; 389 symCount = GROUP_SIZE - 1;
370 if (selector >= nSelectors) return RETVAL_DATA_ERROR; 390 if (selector >= nSelectors)
371 hufGroup = bd->groups + selectors[selector++]; 391 return RETVAL_DATA_ERROR;
392 ngrp = selectors[selector++];
393 if (ngrp >= groupCount) {
394 dbg("%d selectors[%d]:%d groupCount:%d",
395 __LINE__, selector-1, ngrp, groupCount);
396 return RETVAL_DATA_ERROR;
397 }
398 hufGroup = bd->groups + ngrp;
372 base = hufGroup->base - 1; 399 base = hufGroup->base - 1;
373 limit = hufGroup->limit - 1; 400 limit = hufGroup->limit - 1;
374 401
@@ -403,7 +430,8 @@ static int get_next_block(bunzip_data *bd)
403 } 430 }
404 /* Figure how many bits are in next symbol and unget extras */ 431 /* Figure how many bits are in next symbol and unget extras */
405 i = hufGroup->minLen; 432 i = hufGroup->minLen;
406 while (nextSym > limit[i]) ++i; 433 while (nextSym > limit[i])
434 ++i;
407 j = hufGroup->maxLen - i; 435 j = hufGroup->maxLen - i;
408 if (j < 0) 436 if (j < 0)
409 return RETVAL_DATA_ERROR; 437 return RETVAL_DATA_ERROR;
@@ -671,7 +699,10 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
671/* Because bunzip2 is used for help text unpacking, and because bb_show_usage() 699/* Because bunzip2 is used for help text unpacking, and because bb_show_usage()
672 should work for NOFORK applets too, we must be extremely careful to not leak 700 should work for NOFORK applets too, we must be extremely careful to not leak
673 any allocations! */ 701 any allocations! */
674int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, 702int FAST_FUNC start_bunzip(
703 void *jmpbuf,
704 bunzip_data **bdp,
705 int in_fd,
675 const void *inbuf, int len) 706 const void *inbuf, int len)
676{ 707{
677 bunzip_data *bd; 708 bunzip_data *bd;
@@ -683,11 +714,14 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd,
683 714
684 /* Figure out how much data to allocate */ 715 /* Figure out how much data to allocate */
685 i = sizeof(bunzip_data); 716 i = sizeof(bunzip_data);
686 if (in_fd != -1) i += IOBUF_SIZE; 717 if (in_fd != -1)
718 i += IOBUF_SIZE;
687 719
688 /* Allocate bunzip_data. Most fields initialize to zero. */ 720 /* Allocate bunzip_data. Most fields initialize to zero. */
689 bd = *bdp = xzalloc(i); 721 bd = *bdp = xzalloc(i);
690 722
723 bd->jmpbuf = jmpbuf;
724
691 /* Setup input buffer */ 725 /* Setup input buffer */
692 bd->in_fd = in_fd; 726 bd->in_fd = in_fd;
693 if (-1 == in_fd) { 727 if (-1 == in_fd) {
@@ -702,10 +736,6 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd,
702 /* Init the CRC32 table (big endian) */ 736 /* Init the CRC32 table (big endian) */
703 crc32_filltable(bd->crc32Table, 1); 737 crc32_filltable(bd->crc32Table, 1);
704 738
705 /* Setup for I/O error handling via longjmp */
706 i = setjmp(bd->jmpbuf);
707 if (i) return i;
708
709 /* Ensure that file starts with "BZh['1'-'9']." */ 739 /* Ensure that file starts with "BZh['1'-'9']." */
710 /* Update: now caller verifies 1st two bytes, makes .gz/.bz2 740 /* Update: now caller verifies 1st two bytes, makes .gz/.bz2
711 * integration easier */ 741 * integration easier */
@@ -752,8 +782,12 @@ unpack_bz2_stream(transformer_state_t *xstate)
752 outbuf = xmalloc(IOBUF_SIZE); 782 outbuf = xmalloc(IOBUF_SIZE);
753 len = 0; 783 len = 0;
754 while (1) { /* "Process one BZ... stream" loop */ 784 while (1) { /* "Process one BZ... stream" loop */
785 jmp_buf jmpbuf;
755 786
756 i = start_bunzip(&bd, xstate->src_fd, outbuf + 2, len); 787 /* Setup for I/O error handling via longjmp */
788 i = setjmp(jmpbuf);
789 if (i == 0)
790 i = start_bunzip(&jmpbuf, &bd, xstate->src_fd, outbuf + 2, len);
757 791
758 if (i == 0) { 792 if (i == 0) {
759 while (1) { /* "Produce some output bytes" loop */ 793 while (1) { /* "Produce some output bytes" loop */
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index 9a58d10d4..7f9046b82 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -32,7 +32,6 @@
32 * 32 *
33 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 33 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
34 */ 34 */
35#include <setjmp.h>
36#include "libbb.h" 35#include "libbb.h"
37#include "bb_archive.h" 36#include "bb_archive.h"
38 37
diff --git a/coreutils/test.c b/coreutils/test.c
index a8286525a..824ce3b5a 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -76,7 +76,6 @@
76//usage: "1\n" 76//usage: "1\n"
77 77
78#include "libbb.h" 78#include "libbb.h"
79#include <setjmp.h>
80 79
81/* This is a NOFORK applet. Be very careful! */ 80/* This is a NOFORK applet. Be very careful! */
82 81
diff --git a/include/bb_archive.h b/include/bb_archive.h
index a5c61e95b..b437f1920 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -210,7 +210,7 @@ const llist_t *find_list_entry2(const llist_t *list, const char *filename) FAST_
210 210
211/* A bit of bunzip2 internals are exposed for compressed help support: */ 211/* A bit of bunzip2 internals are exposed for compressed help support: */
212typedef struct bunzip_data bunzip_data; 212typedef struct bunzip_data bunzip_data;
213int start_bunzip(bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_FUNC; 213int start_bunzip(void *, bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_FUNC;
214/* NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes 214/* NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes
215 * in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0: */ 215 * in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0: */
216int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; 216int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC;
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 022455da4..769b7881c 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -102,14 +102,21 @@ static const char *unpack_usage_messages(void)
102 char *outbuf = NULL; 102 char *outbuf = NULL;
103 bunzip_data *bd; 103 bunzip_data *bd;
104 int i; 104 int i;
105 jmp_buf jmpbuf;
105 106
106 i = start_bunzip(&bd, 107 /* Setup for I/O error handling via longjmp */
108 i = setjmp(jmpbuf);
109 if (i == 0) {
110 i = start_bunzip(&jmpbuf,
111 &bd,
107 /* src_fd: */ -1, 112 /* src_fd: */ -1,
108 /* inbuf: */ packed_usage, 113 /* inbuf: */ packed_usage,
109 /* len: */ sizeof(packed_usage)); 114 /* len: */ sizeof(packed_usage)
110 /* read_bunzip can longjmp to start_bunzip, and ultimately 115 );
111 * end up here with i != 0 on read data errors! Not trivial */ 116 }
112 if (!i) { 117 /* read_bunzip can longjmp and end up here with i != 0
118 * on read data errors! Not trivial */
119 if (i == 0) {
113 /* Cannot use xmalloc: will leak bd in NOFORK case! */ 120 /* Cannot use xmalloc: will leak bd in NOFORK case! */
114 outbuf = malloc_or_warn(sizeof(UNPACKED_USAGE)); 121 outbuf = malloc_or_warn(sizeof(UNPACKED_USAGE));
115 if (outbuf) 122 if (outbuf)
diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c
index 9ab57876e..501349548 100644
--- a/miscutils/bbconfig.c
+++ b/miscutils/bbconfig.c
@@ -44,13 +44,22 @@ int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
44{ 44{
45#if ENABLE_FEATURE_COMPRESS_BBCONFIG 45#if ENABLE_FEATURE_COMPRESS_BBCONFIG
46 bunzip_data *bd; 46 bunzip_data *bd;
47 int i = start_bunzip(&bd, 47 int i;
48 jmp_buf jmpbuf;
49
50 /* Setup for I/O error handling via longjmp */
51 i = setjmp(jmpbuf);
52 if (i == 0) {
53 i = start_bunzip(&jmpbuf,
54 &bd,
48 /* src_fd: */ -1, 55 /* src_fd: */ -1,
49 /* inbuf: */ bbconfig_config_bz2, 56 /* inbuf: */ bbconfig_config_bz2,
50 /* len: */ sizeof(bbconfig_config_bz2)); 57 /* len: */ sizeof(bbconfig_config_bz2)
51 /* read_bunzip can longjmp to start_bunzip, and ultimately 58 );
52 * end up here with i != 0 on read data errors! Not trivial */ 59 }
53 if (!i) { 60 /* read_bunzip can longjmp and end up here with i != 0
61 * on read data errors! Not trivial */
62 if (i == 0) {
54 /* Cannot use xmalloc: will leak bd in NOFORK case! */ 63 /* Cannot use xmalloc: will leak bd in NOFORK case! */
55 char *outbuf = malloc_or_warn(sizeof(bbconfig_config)); 64 char *outbuf = malloc_or_warn(sizeof(bbconfig_config));
56 if (outbuf) { 65 if (outbuf) {
diff --git a/shell/ash.c b/shell/ash.c
index 56fba4a57..24958c0fc 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -177,7 +177,6 @@
177 177
178#define JOBS ENABLE_ASH_JOB_CONTROL 178#define JOBS ENABLE_ASH_JOB_CONTROL
179 179
180#include <setjmp.h>
181#include <fnmatch.h> 180#include <fnmatch.h>
182#include <sys/times.h> 181#include <sys/times.h>
183#include <sys/utsname.h> /* for setting $HOSTNAME */ 182#include <sys/utsname.h> /* for setting $HOSTNAME */
diff --git a/testsuite/bunzip2.tests b/testsuite/bunzip2.tests
index fcfce1a31..edb332748 100755
--- a/testsuite/bunzip2.tests
+++ b/testsuite/bunzip2.tests
@@ -552,6 +552,22 @@ if test "${0##*/}" = "bunzip2.tests"; then
552 echo "FAIL: $unpack: pbzip_4m_zeros file" 552 echo "FAIL: $unpack: pbzip_4m_zeros file"
553 FAILCOUNT=$((FAILCOUNT + 1)) 553 FAILCOUNT=$((FAILCOUNT + 1))
554 fi 554 fi
555
556 errout="`${bb}bunzip2 <bz2_issue_11.bz2 2>&1 >/dev/null`"
557 if test x"$errout:$?" = x"bunzip2: bunzip error -5:1"; then
558 echo "PASS: $unpack: bz2_issue_11.bz2 corrupted example"
559 else
560 echo "FAIL: $unpack: bz2_issue_11.bz2 corrupted example"
561 FAILCOUNT=$((FAILCOUNT + 1))
562 fi
563
564 errout="`${bb}bunzip2 <bz2_issue_12.bz2 2>&1 >/dev/null`"
565 if test x"$errout:$?" = x"bunzip2: bunzip error -3:1"; then
566 echo "PASS: $unpack: bz2_issue_12.bz2 corrupted example"
567 else
568 echo "FAIL: $unpack: bz2_issue_12.bz2 corrupted example"
569 FAILCOUNT=$((FAILCOUNT + 1))
570 fi
555fi 571fi
556 572
557exit $((FAILCOUNT <= 255 ? FAILCOUNT : 255)) 573exit $((FAILCOUNT <= 255 ? FAILCOUNT : 255))
diff --git a/testsuite/bz2_issue_11.bz2 b/testsuite/bz2_issue_11.bz2
new file mode 100644
index 000000000..62b252046
--- /dev/null
+++ b/testsuite/bz2_issue_11.bz2
Binary files differ
diff --git a/testsuite/bz2_issue_12.bz2 b/testsuite/bz2_issue_12.bz2
new file mode 100644
index 000000000..4215f08d6
--- /dev/null
+++ b/testsuite/bz2_issue_12.bz2
Binary files differ