Merge pull request #3365 from moodyastra/codex/libarchive-lzx-history-guard

cab: reject LZX matches before initialized history
This commit is contained in:
Dustin L. Howett authored and GitHub committed 2026-08-08 14:38:09 -05:00
commit 682a87b111
6 files changed
+81

No files matched your search

+3
View File
@@ -494,6 +494,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_cab_filename.c \
libarchive/test/test_read_format_cab_lzx_16bit.c \
libarchive/test/test_read_format_cab_lzx_e8.c \
libarchive/test/test_read_format_cab_lzx_invalid_history.c \
libarchive/test/test_read_format_cab_lzx_oob.c \
libarchive/test/test_read_format_cab_mszip_oob.c \
libarchive/test/test_read_format_cab_multi.c \
@@ -928,6 +929,8 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_cab_filename_cp932.cab.uu \
libarchive/test/test_read_format_cab_lzx_16bit.cab.uu \
libarchive/test/test_read_format_cab_lzx_e8.cab.uu \
libarchive/test/test_read_format_cab_lzx_invalid_history.cab.uu \
libarchive/test/test_read_format_cab_lzx_literal_control.cab.uu \
libarchive/test/test_read_format_cab_lzx_oob.cab.uu \
libarchive/test/test_read_format_cab_multi.p1.cab.uu \
libarchive/test/test_read_format_cab_multi.p2.cab.uu \
@@ -187,6 +187,8 @@ struct lzx_dec {
uint8_t *w_buff;
/* The insert position to the window. */
size_t w_pos;
/* The number of initialized bytes in the window. */
size_t w_filled;
/* The position where we can copy decoded code from the window. */
size_t copy_pos;
/* The length how many bytes we can copy decoded code from
@@ -2251,6 +2253,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
}
ds->w_pos = 0;
ds->w_filled = 0;
ds->state = ST_RD_TRANSLATION;
ds->br.cache_buffer = 0;
ds->br.cache_avail = 0;
@@ -2706,6 +2709,11 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
strm->avail_out -= l;
strm->total_out += l;
ds->w_pos = (ds->w_pos + l) & ds->w_mask;
if (ds->w_filled < ds->w_size) {
ds->w_filled += l;
if (ds->w_filled > ds->w_size)
ds->w_filled = ds->w_size;
}
ds->block_bytes_avail -= l;
}
/* FALL THROUGH */
@@ -2861,6 +2869,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
uint8_t mt_lookup_bits = mt->lookup_bits;
size_t copy_len = ds->copy_len, copy_pos = ds->copy_pos;
size_t w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
size_t w_filled = ds->w_filled;
uint8_t length_header = ds->length_header;
uint8_t offset_bits = ds->offset_bits;
uint16_t position_slot = ds->position_slot;
@@ -2885,6 +2894,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
ds->position_slot = position_slot;
ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
ds->w_pos = w_pos;
ds->w_filled = w_filled;
strm->avail_out = endp - noutp;
return (ARCHIVE_EOF);
}
@@ -2921,6 +2931,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
* afterward. */
w_buff[w_pos] = c;
w_pos = (w_pos + 1) & w_mask;
if (w_filled < w_size)
w_filled++;
/* Store the decoded code to output buffer. */
*noutp++ = c;
block_bytes_avail--;
@@ -3048,6 +3060,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
/*
* Compute a real position in window.
*/
if (copy_pos == 0 || copy_pos > w_filled)
goto failed;
copy_pos = (w_pos - copy_pos) & w_mask;
/* FALL THROUGH */
case ST_COPY:
@@ -3085,6 +3099,11 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
noutp += l;
copy_pos = (copy_pos + l) & w_mask;
w_pos = (w_pos + l) & w_mask;
if (w_filled < w_size) {
w_filled += l;
if (w_filled > w_size)
w_filled = w_size;
}
block_bytes_avail -= l;
if (copy_len <= l)
/* A copy of current pattern ended. */
@@ -3113,6 +3132,7 @@ next_data:
ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
ds->state = state;
ds->w_pos = w_pos;
ds->w_filled = w_filled;
strm->avail_out = endp - noutp;
return (ARCHIVE_OK);
}
+1
View File
@@ -123,6 +123,7 @@ IF(ENABLE_TEST)
test_read_format_cab_filename.c
test_read_format_cab_lzx_16bit.c
test_read_format_cab_lzx_e8.c
test_read_format_cab_lzx_invalid_history.c
test_read_format_cab_lzx_oob.c
test_read_format_cab_mszip_oob.c
test_read_format_cab_multi.c
@@ -0,0 +1,45 @@
#include "test.h"
DEFINE_TEST(test_read_format_cab_lzx_invalid_history)
{
const char *invalid = "test_read_format_cab_lzx_invalid_history.cab";
const char *control = "test_read_format_cab_lzx_literal_control.cab";
struct archive *a;
struct archive_entry *ae;
char buff[2];
extract_reference_file(invalid);
extract_reference_file(control);
/* A match cannot refer to history that has not been produced yet. */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_cab(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK,
archive_read_open_filename(a, invalid, 10240));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("x", archive_entry_pathname(ae));
assertEqualInt(2, archive_entry_size(ae));
assertEqualIntA(a, ARCHIVE_FATAL,
archive_read_data(a, buff, sizeof(buff)));
assertEqualInt(-1, archive_errno(a));
assertEqualString("LZX decompression failed (-25)",
archive_error_string(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/* The corresponding literal-only stream remains valid. */
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_cab(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK,
archive_read_open_filename(a, control, 10240));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("x", archive_entry_pathname(ae));
assertEqualInt(2, archive_entry_size(ae));
assertEqualIntA(a, sizeof(buff),
archive_read_data(a, buff, sizeof(buff)));
assertEqualMem("\0\0", buff, sizeof(buff));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -0,0 +1,6 @@
begin 644 test_read_format_cab_lzx_invalid_history.cab
M35-#1@````!V`````````"P``````````P$!``$`````````/@````$``P\"
M````````````````````>```````,``"```0(@`````````"``<B_____P"0
<````````$!'_/___@+P```````"(`/^#___`_```
`
end
@@ -0,0 +1,6 @@
begin 644 test_read_format_cab_lzx_literal_control.cab
M35-#1@````!V`````````"P``````````P$!``$`````````/@````$``P\"
M````````````````````>```````,``"```0(@`````````"``<B_____P"0
<````````$!'_/___@+P```````"(`/^#__^`_```
`
end