mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
#1807: test that a zstd block larger than its frame's window is refused
ruzstd 0.9.0 let a block decompress to more than its frame's window allows (RUSTSEC-2026-0344). The test swaps a hand-built Zstandard frame with a 1 KiB window and one 100,000-byte RLE block into an Affinity container entry and checks that reading the entry fails. With ruzstd pinned back to 0.9.0 the block is decompressed and the read succeeds.
This commit is contained in:
committed by
bflatastic
parent
02f5bc8666
commit
8abb1d1c71
@@ -261,6 +261,32 @@ mod archive {
|
||||
assert!(matches!(a.read("doc.dat"), Err(Error::Limit(_))));
|
||||
}
|
||||
|
||||
// Regression test for #1710: ruzstd 0.9.0 let a block decompress to more than its frame's
|
||||
// window allows (RUSTSEC-2026-0344), so a crafted entry made the decoder produce far more than
|
||||
// the format permits for a block. 0.9.1 refuses it.
|
||||
#[test]
|
||||
fn a_zstd_block_larger_than_its_frames_window_is_refused() {
|
||||
const LEN: u32 = 100_000;
|
||||
let plain = vec![0x61u8; LEN as usize];
|
||||
let file = synth::container(&[("doc.dat", &plain, Method::Zstd)], None);
|
||||
// A Zstandard frame with a 1 KiB window (descriptor byte 0, window byte 0) holding one RLE
|
||||
// block, the last, that repeats a byte LEN times: block header = last | RLE << 1 | LEN << 3.
|
||||
let mut frame = vec![0x28, 0xB5, 0x2F, 0xFD, 0x00, 0x00];
|
||||
frame.extend((1 | (1 << 1) | (LEN << 3)).to_le_bytes().get(..3).unwrap());
|
||||
frame.push(0x61);
|
||||
// Swap it in for the entry's compressed bytes (they follow the "#Fil" tag at offset 72).
|
||||
let fat = u64::from_le_bytes(file[16..24].try_into().unwrap()) as usize;
|
||||
let old_len = u64::from_le_bytes(file[fat + 59 + 21..fat + 59 + 29].try_into().unwrap()) as usize;
|
||||
let mut swapped = file[..76].to_vec();
|
||||
swapped.extend(&frame);
|
||||
swapped.extend(&file[76 + old_len..]);
|
||||
let new_fat = fat - old_len + frame.len();
|
||||
swapped[16..24].copy_from_slice(&(new_fat as u64).to_le_bytes());
|
||||
swapped[new_fat + 59 + 21..new_fat + 59 + 29].copy_from_slice(&(frame.len() as u64).to_le_bytes());
|
||||
let mut a = Archive::open(&swapped, Limits::default()).unwrap();
|
||||
assert!(a.read("doc.dat").is_err(), "a block of {LEN} bytes was decompressed from a frame with a 1 KiB window");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_declared_size_smaller_than_the_data_is_rejected_not_truncated() {
|
||||
let big = vec![7u8; 1 << 20];
|
||||
|
||||
Reference in New Issue
Block a user