diff --git a/crates/engine/src/cmd/fileio/pxrread.rs b/crates/engine/src/cmd/fileio/pxrread.rs index eb7957ad9..fc3a32f15 100644 --- a/crates/engine/src/cmd/fileio/pxrread.rs +++ b/crates/engine/src/cmd/fileio/pxrread.rs @@ -24,8 +24,8 @@ const TRUNCATED: &str = "the Pixar file is cut short"; /// define. const DAMAGED: &str = "the Pixar file's header is damaged"; -/// The message for encoded tile data with a packet the format doesn't define, or one that runs -/// past the end of its scan line. +/// The message for a tile pointer into the header or the tile pointer table, and for encoded tile +/// data with a packet the format doesn't define, or one that runs past the end of its scan line. const BAD_DATA: &str = "the Pixar file's image data is damaged"; /// The channel bits of the picture format field (header byte 424): R, G, B and A, stored in this @@ -115,7 +115,9 @@ pub(super) fn decode(bytes: &[u8], max_alloc: u64) -> Result Result= bytes.len() { return Err(TRUNCATED.into()); } + // Tile data follows the tile pointer table; a pointer into the header or the table would + // read them as pixels. + if pointer < table_end { + return Err(BAD_DATA.into()); + } let (x0, y0) = (n % across * tile_w, n / across * tile_h); // The part of the tile inside the picture; the pixels of border tiles past its edges are // stored and skipped. diff --git a/crates/engine/src/cmd/fileio/tests_pxrread.rs b/crates/engine/src/cmd/fileio/tests_pxrread.rs index 0562aacbb..f9e89e38f 100644 --- a/crates/engine/src/cmd/fileio/tests_pxrread.rs +++ b/crates/engine/src/cmd/fileio/tests_pxrread.rs @@ -361,3 +361,17 @@ fn damaged_files_are_refused_with_a_message() { assert!(!is_pxr(&bad), "{bad:?}"); } } + +#[test] +fn tile_pointers_into_the_header_or_table_are_refused() { + // Tile data follows the tile pointer table, which ends at byte 520 in a one-tile picture. + let rgb = one(head(2, 1, RGB, 2), &[1, 2, 3, 4, 5, 6]); + for pointer in [4u32, 511, 512, 519] { + let mut inside = rgb.clone(); + inside[512..516].copy_from_slice(&pointer.to_le_bytes()); + let e = raster_image(&inside).err().expect("refused").to_string(); + assert_eq!(e, "the Pixar file's image data is damaged", "a pointer to byte {pointer}"); + } + // A pointer at the table's end reads. + assert_eq!(pixels(&rgb), [[1, 2, 3, 255], [4, 5, 6, 255]]); +}