From f0b08e9dea63b4ff03340c647b29b8c6c02e0249 Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Sun, 22 Oct 2023 19:47:50 +0200 Subject: [PATCH] LibCompress: Process XZ filters in reverse order XZ writes filters in the order that they are used during compression, so we need to process them in the reverse order while decompression. This wasn't noticed earlier because we only supported the LZMA2 filter. --- Userland/Libraries/LibCompress/Xz.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibCompress/Xz.cpp b/Userland/Libraries/LibCompress/Xz.cpp index 9933678af0..2615de91e1 100644 --- a/Userland/Libraries/LibCompress/Xz.cpp +++ b/Userland/Libraries/LibCompress/Xz.cpp @@ -316,6 +316,13 @@ ErrorOr XzDecompressor::load_next_block(u8 encoded_block_header_size) m_current_block_expected_uncompressed_size.clear(); } + // We need to process the filters in reverse order, since they are listed in the order that they have been applied in. + struct FilterEntry { + u64 id; + ByteBuffer properties; + }; + Vector 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)." @@ -330,12 +337,16 @@ ErrorOr 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)); + } + + for (auto& filter : filters.in_reverse()) { // 5.3.1. LZMA2 - if (filter_id == 0x21) { - if (size_of_properties < sizeof(XzFilterLzma2Properties)) + if (filter.id == 0x21) { + if (filter.properties.size() < sizeof(XzFilterLzma2Properties)) return Error::from_string_literal("XZ LZMA2 filter has a smaller-than-needed properties size"); - auto const* properties = reinterpret_cast(filter_properties.data()); + auto const* properties = reinterpret_cast(filter.properties.data()); TRY(properties->validate()); new_block_stream = TRY(Lzma2Decompressor::create_from_raw_stream(move(new_block_stream), properties->dictionary_size()));