From 9aebc8ba51649314c623bca2f5bc971b2049b6da Mon Sep 17 00:00:00 2001 From: MarekSpodBiedry <73122968+MarekSpodBiedry@users.noreply.github.com> Date: Tue, 13 Oct 2026 17:35:47 +0200 Subject: [PATCH] AV1: reject tile groups that repeat, skip or reorder tiles (#395) --- crates/av1/src/decoder.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/crates/av1/src/decoder.rs b/crates/av1/src/decoder.rs index 66c96698..6a52902a 100644 --- a/crates/av1/src/decoder.rs +++ b/crates/av1/src/decoder.rs @@ -555,6 +555,7 @@ impl Decoder { if tg_end >= num_tiles || tg_start > tg_end { return Err(Error::Invalid("tile group range")); } + check_tile_group_start(job.tiles.len(), tg_start)?; let mut pos = r.byte_pos(); for tile_num in tg_start..=tg_end { let size = if tile_num == tg_end { @@ -947,3 +948,26 @@ fn project(fs: &mut FrameState, src: usize, dst_sign: i32) -> bool { } true } + +/// Tile groups must arrive in order with no gaps and no overlap: each one starts at the tile +/// after the last one received (`tg_start` semantics, 6.10.1). +fn check_tile_group_start(received: usize, tg_start: usize) -> Result<()> { + if tg_start == received { Ok(()) } else { Err(Error::Invalid("tile group out of order")) } +} + +#[cfg(test)] +mod tests { + use super::check_tile_group_start; + + #[test] + fn tile_groups_must_be_contiguous() { + assert!(check_tile_group_start(0, 0).is_ok()); + assert!(check_tile_group_start(2, 2).is_ok()); + // duplicate coverage + assert!(check_tile_group_start(2, 0).is_err()); + assert!(check_tile_group_start(2, 1).is_err()); + // skipped tiles + assert!(check_tile_group_start(0, 1).is_err()); + assert!(check_tile_group_start(2, 3).is_err()); + } +}