From 8d3e4a630f3657732fddcb9a4f20001e37c5b847 Mon Sep 17 00:00:00 2001 From: midasmatterhorn <248507632+midasmatterhorn@users.noreply.github.com> Date: Thu, 15 Oct 2026 03:07:22 +0300 Subject: [PATCH] fix(media): prevent overflow while probing ASF headers Use checked arithmetic for ASF header-object bounds and cursor advances so hostile object sizes cannot panic. Keep a synthetic regression for the malformed header. Addresses #750 (ASF object-size overflow). --- crates/media/src/probe.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/crates/media/src/probe.rs b/crates/media/src/probe.rs index cf5de96a..2453317a 100644 --- a/crates/media/src/probe.rs +++ b/crates/media/src/probe.rs @@ -198,8 +198,8 @@ fn probe_asf(b: &[u8]) -> Result { } let header_end = (u64le(16) as usize).min(b.len()); let mut info = MediaInfo { container: "asf", ..Default::default() }; - let mut pos = 30; - while pos + 24 <= header_end { + let mut pos: usize = 30; + while pos.checked_add(24).is_some_and(|end| end <= header_end) { let guid = &b[pos..pos + 16]; let size = u64le(pos + 16) as usize; if size < 24 { @@ -230,7 +230,24 @@ fn probe_asf(b: &[u8]) -> Result { info.video = Some(VideoInfo { codec: "WMV".into(), width: u32le(td), height: u32le(td + 4), decodable: false, ..Default::default() }); } } - pos += size; + // A hostile size must not wrap the walk (or walk off the end): an object that + // overruns the header ends it, which is also the correct ASF semantics. + let Some(next) = pos.checked_add(size).filter(|&p| p <= header_end) else { break }; + pos = next; } Ok(info) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hostile_asf_object_sizes_end_the_walk() { + // The header object GUID followed by 48 × 0xFF: the walk reads usize::MAX back as + // every object size and must end instead of wrapping `pos` (and panicking). + let mut b = crate::ASF_HEADER.to_vec(); + b.extend_from_slice(&[0xFF; 48]); + assert!(matches!(probe_asf(&b), Ok(info) if info.container == "asf")); + } +}