Compare commits

...

2 Commits

Author SHA1 Message Date
Jessa
6b5705c32e don't panic on truncated reserved bytes
Some checks failed
test / format-check (push) Has been cancelled
test / check-nightly (push) Has been cancelled
test / build-and-test (push) Has been cancelled
test / fuzz-afl (push) Has been cancelled
test / fuzz-libfuzzer (push) Has been cancelled
currently the only caller, Vp8xChunk, validates input length, so the
panic isn't reachable from the top-level sanitize. but the parse fn is
public, so we shouldn't have a panicking path like that.

Signed-off-by: Jessa <git@jessa0.com>
Assisted-by: Claude:claude-opus-4-7
2026-04-26 10:02:48 -07:00
Jessa
f4e4fc2e58 dont allocate more than input remaining
Signed-off-by: Jessa <git@jessa0.com>
Assisted-by: Claude:claude-opus-4-7
2026-04-26 10:02:48 -07:00
3 changed files with 48 additions and 1 deletions

View File

@ -603,6 +603,23 @@ mod test {
sanitize(test).unwrap_err();
}
#[test]
fn moov_truncated() {
init_logger();
let mut data = vec![];
test_ftyp().build().put_buf(&mut data);
write_test_mdat(&mut data, b"");
// moov header claims 900 MiB of body, but only 4 bytes follow.
BoxHeader::with_u32_data_size(MOOV, 900 * 1024 * 1024).put_buf(&mut data);
data.extend_from_slice(&[0u8; 4]);
assert_matches!(sanitize(io::Cursor::new(&data)).unwrap_err(), Error::Parse(err) => {
assert_matches!(err.into_inner(), ParseError::TruncatedBox);
});
}
#[test]
fn ftyp_too_large() {
let mut compatible_brands = vec![];

View File

@ -84,10 +84,16 @@ impl<T: ParsedBox + ?Sized> Mp4Box<T> {
R: AsyncRead + AsyncSkip,
T: ParseBox,
{
let reader_remaining = reader.as_mut().stream_len().await? - reader.as_mut().stream_position().await?;
let box_data_size = match header.box_data_size()? {
Some(box_data_size) => box_data_size,
None => reader.as_mut().stream_len().await? - reader.as_mut().stream_position().await?,
None => reader_remaining,
};
ensure_attach!(
box_data_size <= reader_remaining,
ParseError::TruncatedBox,
WhileParsingBox(header.box_type()),
);
ensure_attach!(
box_data_size <= max_size,

View File

@ -174,6 +174,11 @@ impl<const LEN: u32> WebmPrim for Reserved<LEN> {
const ENCODED_LEN: u32 = LEN;
fn parse<B: Buf>(mut buf: B) -> Result<Self, ParseError> {
ensure_attach!(
buf.remaining() >= Self::ENCODED_LEN as usize,
ParseError::TruncatedChunk,
WhileParsingType::new::<Self>(),
);
for _ in 0..LEN {
ensure_attach!(
buf.get_u8() == 0,
@ -191,3 +196,22 @@ impl<const LEN: u32> WebmPrim for Reserved<LEN> {
}
}
}
#[cfg(test)]
mod test {
use bytes::BytesMut;
use super::*;
#[test]
fn reserved_truncated() {
let err = Reserved::<3>::parse(&mut BytesMut::from(&[0, 0][..])).unwrap_err();
assert!(matches!(err.get_ref(), ParseError::TruncatedChunk), "{err}");
}
#[test]
fn reserved_truncated_empty() {
let err = Reserved::<1>::parse(&mut BytesMut::new()).unwrap_err();
assert!(matches!(err.get_ref(), ParseError::TruncatedChunk), "{err}");
}
}