mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-24 09:57:08 -06:00
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)
This commit is contained in:
@@ -114,11 +114,23 @@ pub(crate) fn read_craw(t: &Tiff, ifd: &Ifd, limits: &Limits) -> Result<Plane> {
|
|||||||
}
|
}
|
||||||
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)"))?;
|
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)?;
|
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.
|
// One byte per pixel: locate every row in the strips.
|
||||||
let mut rows: Vec<&[u8]> = Vec::with_capacity(height);
|
let mut rows: Vec<&[u8]> = Vec::with_capacity(height);
|
||||||
for s in segments(t, ifd, width, height)? {
|
for s in segments(t, ifd, width, height)? {
|
||||||
let n = s.h.min(height.saturating_sub(s.y));
|
let n = s.h.min(height.saturating_sub(s.y));
|
||||||
for r in 0..n {
|
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"))?;
|
let at = s.offset.checked_add(r * width).ok_or_else(|| RawError::malformed("raw strip offset overflows"))?;
|
||||||
if (r + 1) * width > s.len {
|
if (r + 1) * width > s.len {
|
||||||
return Err(RawError::malformed("compressed ARW strip is shorter than its rows"));
|
return Err(RawError::malformed("compressed ARW strip is shorter than its rows"));
|
||||||
|
|||||||
Reference in New Issue
Block a user