busybox-1.27.2: Fix lzma segfaults [No upstream tracking] -- https://bugs.busybox.net/show_bug.cgi?id=10871 libarchive: check buffer index in lzma_decompress With specific defconfig busybox fails to check zip fileheader magic (archival/unzip.c) and uses (archival/libarchive/decompress_unlzma.c) for decompression which leads to segmentation fault. It prevents accessing into buffer, which is smaller than pos index. Patch includes multiple segmentation fault fixes. Upstream-Status: Backport [https://git.busybox.net/busybox/commit/?id=a36986bb80289c1cd8d15a557e49207c9a42946b] bug: 10436 10871 Signed-off-by: Andrej Valek diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index a904087..29eee2a 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c @@ -11,6 +11,14 @@ #include "libbb.h" #include "bb_archive.h" + +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + + #if ENABLE_FEATURE_LZMA_FAST # define speed_inline ALWAYS_INLINE # define size_inline @@ -217,6 +225,7 @@ unpack_lzma_stream(transformer_state_t *xstate) rc_t *rc; int i; uint8_t *buffer; + uint32_t buffer_size; uint8_t previous_byte = 0; size_t buffer_pos = 0, global_pos = 0; int len = 0; @@ -246,7 +255,8 @@ unpack_lzma_stream(transformer_state_t *xstate) if (header.dict_size == 0) header.dict_size++; - buffer = xmalloc(MIN(header.dst_size, header.dict_size)); + buffer_size = MIN(header.dst_size, header.dict_size); + buffer = xmalloc(buffer_size); { int num_probs; @@ -341,8 +351,12 @@ unpack_lzma_stream(transformer_state_t *xstate) state = state < LZMA_NUM_LIT_STATES ? 9 : 11; pos = buffer_pos - rep0; - if ((int32_t)pos < 0) + if ((int32_t)pos < 0) { pos += header.dict_size; + /* see unzip_bad_lzma_2.zip: */ + if (pos >= buffer_size) + goto bad; + } previous_byte = buffer[pos]; goto one_byte1; #else @@ -417,6 +431,10 @@ unpack_lzma_stream(transformer_state_t *xstate) for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--) rep0 = (rep0 << 1) | rc_direct_bit(rc); rep0 <<= LZMA_NUM_ALIGN_BITS; + if ((int32_t)rep0 < 0) { + dbg("%d rep0:%d", __LINE__, rep0); + goto bad; + } prob3 = p + LZMA_ALIGN; } i2 = 1; @@ -450,8 +468,12 @@ unpack_lzma_stream(transformer_state_t *xstate) IF_NOT_FEATURE_LZMA_FAST(string:) do { uint32_t pos = buffer_pos - rep0; - if ((int32_t)pos < 0) + if ((int32_t)pos < 0) { pos += header.dict_size; + /* more stringent test (see unzip_bad_lzma_1.zip): */ + if (pos >= buffer_size) + goto bad; + } previous_byte = buffer[pos]; IF_NOT_FEATURE_LZMA_FAST(one_byte2:) buffer[buffer_pos++] = previous_byte; @@ -478,6 +500,12 @@ unpack_lzma_stream(transformer_state_t *xstate) IF_DESKTOP(total_written += buffer_pos;) if (transformer_write(xstate, buffer, buffer_pos) != (ssize_t)buffer_pos) { bad: + /* One of our users, bbunpack(), expects _us_ to emit + * the error message (since it's the best place to give + * potentially more detailed information). + * Do not fail silently. + */ + bb_error_msg("corrupted data"); total_written = -1; /* failure */ } rc_free(rc);