Merge PR #2628: raw: CR3 preview box scan checks 32-bit lengths for overflow (#2569)

This commit is contained in:
aiongg
2026-10-31 02:10:08 +00:00
2 changed files with 18 additions and 2 deletions
+4 -2
View File
@@ -438,10 +438,12 @@ fn cr3_preview_boxes(bytes: &[u8]) -> Option<&[u8]> {
let be32 = |at: usize| bytes.get(at..at + 4).map(|s| u32::from_be_bytes([s[0], s[1], s[2], s[3]]) as usize);
let (Some(size), Some(len)) = (be32(start), be32(start + 20)) else { continue };
let j = start + 24;
if len < 4 || j + len > start + size.max(24) || j + len > bytes.len() {
// 32-bit box lengths can wrap `usize` on wasm32: check the sums, then slice with `get`
let (Some(end), Some(lim)) = (j.checked_add(len), start.checked_add(size.max(24))) else { continue };
if len < 4 || end > lim {
continue;
}
let jpeg = &bytes[j..j + len];
let Some(jpeg) = bytes.get(j..end) else { continue };
// One that doesn't fit the budget left is skipped; a smaller one later may still fit.
if walked + jpeg.len() > CR3_MAX_WALK {
continue;
+14
View File
@@ -199,6 +199,20 @@ fn picks_largest_dct_jpeg() {
}
}
/// #2569: `PRVW` box and JPEG lengths near `u32::MAX` (which wrap `usize` on wasm32) find no preview, never panic.
#[test]
fn cr3_preview_box_huge_lengths_are_rejected() {
let j = fake_jpeg(300);
for (size, len) in [(u32::MAX, u32::MAX), (u32::MAX, u32::MAX - 23), (24 + j.len() as u32, u32::MAX - 3)] {
let mut cr3 = b"\x00\x00\x00\x18ftypcrx \x00\x00\x00\x01crx isom".to_vec();
cr3.extend_from_slice(&size.to_be_bytes());
cr3.extend_from_slice(b"PRVW\x00\x00\x00\x00\x00\x01\x06T\x048\x00\x01");
cr3.extend_from_slice(&len.to_be_bytes());
cr3.extend_from_slice(&j);
assert_eq!(cr3_preview_boxes(&cr3), None, "size {size:#x}, len {len:#x}");
}
}
/// A JPEG like [`fake_jpeg`] whose frame header says `w` x `h` with `nc` components.
fn sized_jpeg(w: u16, h: u16, nc: u8, n: usize) -> Vec<u8> {
let mut j = vec![0xff, 0xd8, 0xff, 0xc0, 0x00, 8 + 3 * nc, 8];