Merge pull request #3365 from moodyastra/codex/libarchive-lzx-history-guard
cab: reject LZX matches before initialized history
This commit is contained in:
6 files changed
+81
No files matched your search
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in new issue
Block a user