Summary
On 32-bit targets (target_pointer_width = "32"), lz4_flex::block::decompress_into can panic due to arithmetic overflow in safe decode path at src/block/decompress_safe.rs:223 (match_length += ...), instead of returning DecompressError.
PoC / UT
#[cfg(all(feature = "safe-decode", target_pointer_width = "32"))]
#[test]
fn PoC() {
// token: literal len = 0, match nibble = 15 => initial match_length = 19
let mut input = vec![0x0F, 0x01, 0x00];
// Build extended match length so read_integer returns usize::MAX - 18 on 32-bit
input.extend(std::iter::repeat(0xFFu8).take(16_843_008));
input.push(0xED);
let mut output = [0u8; 32];
let _ = lz4_flex::block::decompress_into(&input, &mut output);
}
Root Cause
When token low nibble is 0xF, code sets match_length = 19 and then does:
match_length += read_integer(...) as usize (decompress_safe.rs:223).
On 32-bit, crafted extension bytes can make read_integer return a near-usize::MAX value, so this addition overflows and panics.
Thank you lz4_flex developers and maintainers!!
Summary
On 32-bit targets (target_pointer_width = "32"), lz4_flex::block::decompress_into can panic due to arithmetic overflow in safe decode path at src/block/decompress_safe.rs:223 (match_length += ...), instead of returning DecompressError.
PoC / UT
Root Cause
When token low nibble is
0xF, code setsmatch_length = 19and then does:match_length += read_integer(...) as usize(decompress_safe.rs:223).On 32-bit, crafted extension bytes can make read_integer return a near-usize::MAX value, so this addition overflows and panics.
Thank you lz4_flex developers and maintainers!!