From c5a6afcf68f4906257c4d717859a165431f44947 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 21 Oct 2026 22:27:22 -0400 Subject: [PATCH] security(raw): reject tiled Sony cRAW and cap row references read_craw treats every segment as a run of full-width image rows and grew the row-reference vector before checking coverage. A tiled layout (which does not describe full-width rows) with repeated tile offsets could push far more than height rows, allocating gigabytes before the post-loop coverage check ran. Reject tiled cRAW layouts up front (cRAW is only stored as strips) and stop collecting rows once the image height is reached. Finding: 3c2601a1-ad92-45b6-96f7-be5da87d97eb (CWE-400) --- crates/raw/src/sony.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/raw/src/sony.rs b/crates/raw/src/sony.rs index e1961680df..b00fd0360a 100644 --- a/crates/raw/src/sony.rs +++ b/crates/raw/src/sony.rs @@ -114,11 +114,23 @@ pub(crate) fn read_craw(t: &Tiff, ifd: &Ifd, limits: &Limits) -> Result { } let lut = tone_lut(&t.tag_uints(ifd, SONY_TONE_CURVE)).ok_or_else(|| RawError::unsupported("Sony compressed ARW without a usable tone curve (0x7010)"))?; limits.check(width as u64, height as u64, 2)?; + // The cRAW reader treats every segment as a sequence of full-width image rows. A tiled + // layout does not describe full-width rows, so accepting one would let repeated tile + // offsets push far more than `height` row references before the coverage check below. + // cRAW is only stored as strips, so reject tiles outright. + if t.tag_uint(ifd, tag::TILE_WIDTH).is_some() || t.tag_uint(ifd, tag::TILE_LENGTH).is_some() { + return Err(RawError::unsupported("tiled Sony compressed ARW is not supported")); + } // One byte per pixel: locate every row in the strips. let mut rows: Vec<&[u8]> = Vec::with_capacity(height); for s in segments(t, ifd, width, height)? { let n = s.h.min(height.saturating_sub(s.y)); for r in 0..n { + // Never collect more rows than the image has; a malformed strip layout cannot + // grow the reference buffer past the image height. + if rows.len() >= height { + return Err(RawError::malformed("compressed ARW strips describe more rows than the image")); + } let at = s.offset.checked_add(r * width).ok_or_else(|| RawError::malformed("raw strip offset overflows"))?; if (r + 1) * width > s.len { return Err(RawError::malformed("compressed ARW strip is shorter than its rows"));