Skip to content

Commit

Permalink
LibCompress: Implement correct validation of last filters
Browse files Browse the repository at this point in the history
  • Loading branch information
timschumi authored and gmta committed Oct 29, 2023
1 parent 786e654 commit 25642df
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 6 deletions.
3 changes: 0 additions & 3 deletions Tests/LibCompress/TestXz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1864,9 +1864,6 @@ TEST_CASE(xz_utils_unsupported_filter_flags_2)
auto stream = MUST(try_make<FixedMemoryStream>(compressed));
auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));

// TODO: We don't yet check whether the filter chain satisfies the "can't be the last filter"
// requirement. We just happen to get the result right because we try to uncompress the
// test case and fail.
auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
EXPECT(buffer_or_error.is_error());
}
Expand Down
13 changes: 11 additions & 2 deletions Userland/Libraries/LibCompress/Xz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ u32 XzStreamFooter::backward_size() const
return (encoded_backward_size + 1) * 4;
}

u8 XzBlockFlags::number_of_filters() const
size_t XzBlockFlags::number_of_filters() const
{
// 3.1.2. Block Flags:
// "Bit(s) Mask Description
Expand Down Expand Up @@ -380,13 +380,16 @@ ErrorOr<void> XzDecompressor::load_next_block(u8 encoded_block_header_size)
struct FilterEntry {
u64 id;
ByteBuffer properties;
bool last;
};
Vector<FilterEntry, 4> filters;

// 3.1.5. List of Filter Flags:
// "The number of Filter Flags fields is stored in the Block Flags
// field (see Section 3.1.2)."
for (size_t i = 0; i < flags.number_of_filters(); i++) {
auto last = (i == flags.number_of_filters() - 1);

// "The format of each Filter Flags field is as follows:
// Both Filter ID and Size of Properties are stored using the
// encoding described in Section 1.2."
Expand All @@ -397,12 +400,15 @@ ErrorOr<void> XzDecompressor::load_next_block(u8 encoded_block_header_size)
auto filter_properties = TRY(ByteBuffer::create_uninitialized(size_of_properties));
TRY(header_stream.read_until_filled(filter_properties));

filters.empend(filter_id, move(filter_properties));
filters.empend(filter_id, move(filter_properties), last);
}

for (auto& filter : filters.in_reverse()) {
// 5.3.1. LZMA2
if (filter.id == 0x21) {
if (!filter.last)
return Error::from_string_literal("XZ LZMA2 filter can only be the last filter");

if (filter.properties.size() < sizeof(XzFilterLzma2Properties))
return Error::from_string_literal("XZ LZMA2 filter has a smaller-than-needed properties size");

Expand All @@ -415,6 +421,9 @@ ErrorOr<void> XzDecompressor::load_next_block(u8 encoded_block_header_size)

// 5.3.3. Delta
if (filter.id == 0x03) {
if (filter.last)
return Error::from_string_literal("XZ Delta filter can only be a non-last filter");

if (filter.properties.size() < sizeof(XzFilterDeltaProperties))
return Error::from_string_literal("XZ Delta filter has a smaller-than-needed properties size");

Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibCompress/Xz.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ struct [[gnu::packed]] XzBlockFlags {
bool compressed_size_present : 1;
bool uncompressed_size_present : 1;

u8 number_of_filters() const;
size_t number_of_filters() const;
};
static_assert(sizeof(XzBlockFlags) == 1);

Expand Down

0 comments on commit 25642df

Please sign in to comment.