Subject: [PATCH] unlzma: fix a case where we could read before beginning of buffer

From: Denys Vlasenko <[email-masked]>
Date: Tue, 15 Jun 2021 15:07:57 +0200

Testcase:

  21 01 01 00 00 00 00 00 e7 01 01 01 ef 00 df b6
  00 17 02 10 11 0f ff 00 16 00 00

Unfortunately, the bug is not reliably causing a segfault,
the behavior depends on what's in memory before the buffer.

function                                             old     new   delta
unpack_lzma_stream                                  2762    2768      +6

Signed-off-by: Denys Vlasenko <[email-masked]>

Signed-off-by: Pavel Zhukov <[email-masked]>

CVE: CVE-2021-42374
Upstream-Status: Backport [https://git.busybox.net/busybox/commit/?h=1_33_stable&id=d326be2850ea2bd78fe2c22d6c45c3b861d82937]
Comment: testdata dropped because of binary format

---
 archival/libarchive/decompress_unlzma.c |   5 ++++-
 testsuite/unlzma.tests                  |  17 +++++++++++++----
 testsuite/unlzma_issue_3.lzma           | Bin 0 -> 27 bytes
 3 files changed, 17 insertions(+), 5 deletions(-)
 create mode 100644 testsuite/unlzma_issue_3.lzma

diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index 0744f231a1d64d92676b0cada2342f88f3b39b31..fb5aac8fe9ea0c53e0c2d7a7cbd05a753e39bc9d 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -290,8 +290,11 @@ unpack_lzma_stream(transformer_state_t *xstate)
 				uint32_t pos;
 
 				pos = buffer_pos - rep0;
-				if ((int32_t)pos < 0)
+				if ((int32_t)pos < 0) {
 					pos += header.dict_size;
+					if ((int32_t)pos < 0)
+						goto bad;
+				}
 				match_byte = buffer[pos];
 				do {
 					int bit;
-- 
2.34.0