diff --git a/src/mp4box/avc1.rs b/src/mp4box/avc1.rs index 0e6d727..7174122 100644 --- a/src/mp4box/avc1.rs +++ b/src/mp4box/avc1.rs @@ -103,6 +103,11 @@ impl ReadBox<&mut R> for Avc1Box { let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "avc1 box contains a box with a larger size than it", + )); + } if name == BoxType::AvcCBox { let avcc = AvcCBox::read_box(reader, s)?; diff --git a/src/mp4box/co64.rs b/src/mp4box/co64.rs index a7ea68a..978137e 100644 --- a/src/mp4box/co64.rs +++ b/src/mp4box/co64.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -48,7 +49,20 @@ impl ReadBox<&mut R> for Co64Box { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; + let other_size = size_of::(); // entry_count + let entry_size = size_of::(); // chunk_offset let entry_count = reader.read_u32::()?; + if u64::from(entry_count) + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + / entry_size as u64 + { + return Err(Error::InvalidData( + "co64 entry_count indicates more entries than could fit in the box", + )); + } let mut entries = Vec::with_capacity(entry_count as usize); for _i in 0..entry_count { let chunk_offset = reader.read_u64::()?; diff --git a/src/mp4box/ctts.rs b/src/mp4box/ctts.rs index f0ed002..673e8c9 100644 --- a/src/mp4box/ctts.rs +++ b/src/mp4box/ctts.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -54,7 +55,21 @@ impl ReadBox<&mut R> for CttsBox { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; let entry_count = reader.read_u32::()?; + let entry_size = size_of::() + size_of::(); // sample_count + sample_offset + // (sample_offset might be a u32, but the size is the same.) + let other_size = size_of::(); // entry_count + if u64::from(entry_count) + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + / entry_size as u64 + { + return Err(Error::InvalidData( + "ctts entry_count indicates more entries than could fit in the box", + )); + } let mut entries = Vec::with_capacity(entry_count as usize); for _ in 0..entry_count { let entry = CttsEntry { diff --git a/src/mp4box/dinf.rs b/src/mp4box/dinf.rs index b404ae9..46698c9 100644 --- a/src/mp4box/dinf.rs +++ b/src/mp4box/dinf.rs @@ -49,6 +49,11 @@ impl ReadBox<&mut R> for DinfBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "dinf box contains a box with a larger size than it", + )); + } match name { BoxType::DrefBox => { @@ -156,6 +161,11 @@ impl ReadBox<&mut R> for DrefBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "dinf box contains a box with a larger size than it", + )); + } match name { BoxType::UrlBox => { @@ -254,7 +264,7 @@ impl ReadBox<&mut R> for UrlBox { let (version, flags) = read_box_header_ext(reader)?; - let location = if size - HEADER_SIZE - HEADER_EXT_SIZE > 0 { + let location = if size.saturating_sub(HEADER_SIZE + HEADER_EXT_SIZE) > 0 { let buf_size = size - HEADER_SIZE - HEADER_EXT_SIZE - 1; let mut buf = vec![0u8; buf_size as usize]; reader.read_exact(&mut buf)?; diff --git a/src/mp4box/edts.rs b/src/mp4box/edts.rs index 2d55357..9077bb1 100644 --- a/src/mp4box/edts.rs +++ b/src/mp4box/edts.rs @@ -54,6 +54,11 @@ impl ReadBox<&mut R> for EdtsBox { let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "edts box contains a box with a larger size than it", + )); + } if let BoxType::ElstBox = name { let elst = ElstBox::read_box(reader, s)?; diff --git a/src/mp4box/elst.rs b/src/mp4box/elst.rs index 1c48952..297fb63 100644 --- a/src/mp4box/elst.rs +++ b/src/mp4box/elst.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -62,7 +63,29 @@ impl ReadBox<&mut R> for ElstBox { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; let entry_count = reader.read_u32::()?; + let other_size = size_of::(); // entry_count + let entry_size = { + let mut entry_size = 0; + entry_size += if version == 1 { + size_of::() + size_of::() // segment_duration + media_time + } else { + size_of::() + size_of::() // segment_duration + media_time + }; + entry_size += size_of::() + size_of::(); // media_rate_integer + media_rate_fraction + entry_size + }; + if u64::from(entry_count) + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + / entry_size as u64 + { + return Err(Error::InvalidData( + "elst entry_count indicates more entries than could fit in the box", + )); + } let mut entries = Vec::with_capacity(entry_count as usize); for _ in 0..entry_count { let (segment_duration, media_time) = if version == 1 { diff --git a/src/mp4box/ftyp.rs b/src/mp4box/ftyp.rs index ba1358d..789cd4e 100644 --- a/src/mp4box/ftyp.rs +++ b/src/mp4box/ftyp.rs @@ -53,12 +53,12 @@ impl ReadBox<&mut R> for FtypBox { fn read_box(reader: &mut R, size: u64) -> Result { let start = box_start(reader)?; - let major = reader.read_u32::()?; - let minor = reader.read_u32::()?; - if size % 4 != 0 { - return Err(Error::InvalidData("invalid ftyp size")); + if size < 16 || size % 4 != 0 { + return Err(Error::InvalidData("ftyp size too small or not aligned")); } let brand_count = (size - 16) / 4; // header + major + minor + let major = reader.read_u32::()?; + let minor = reader.read_u32::()?; let mut brands = Vec::new(); for _ in 0..brand_count { diff --git a/src/mp4box/hdlr.rs b/src/mp4box/hdlr.rs index 9fb0368..1ff559e 100644 --- a/src/mp4box/hdlr.rs +++ b/src/mp4box/hdlr.rs @@ -52,7 +52,9 @@ impl ReadBox<&mut R> for HdlrBox { skip_bytes(reader, 12)?; // reserved - let buf_size = size - HEADER_SIZE - HEADER_EXT_SIZE - 20 - 1; + let buf_size = size + .checked_sub(HEADER_SIZE + HEADER_EXT_SIZE + 20 + 1) + .ok_or(Error::InvalidData("hdlr size too small"))?; let mut buf = vec![0u8; buf_size as usize]; reader.read_exact(&mut buf)?; diff --git a/src/mp4box/hev1.rs b/src/mp4box/hev1.rs index b566aaa..3a8cfea 100644 --- a/src/mp4box/hev1.rs +++ b/src/mp4box/hev1.rs @@ -103,6 +103,11 @@ impl ReadBox<&mut R> for Hev1Box { let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "hev1 box contains a box with a larger size than it", + )); + } if name == BoxType::HvcCBox { let hvcc = HvcCBox::read_box(reader, s)?; diff --git a/src/mp4box/ilst.rs b/src/mp4box/ilst.rs index 19b0f91..d0292a3 100644 --- a/src/mp4box/ilst.rs +++ b/src/mp4box/ilst.rs @@ -58,6 +58,11 @@ impl ReadBox<&mut R> for IlstBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "ilst box contains a box with a larger size than it", + )); + } match name { BoxType::NameBox => { @@ -129,6 +134,11 @@ impl ReadBox<&mut R> for IlstItemBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "ilst item box contains a box with a larger size than it", + )); + } match name { BoxType::DataBox => { diff --git a/src/mp4box/mdia.rs b/src/mp4box/mdia.rs index 8279ea2..423bf72 100644 --- a/src/mp4box/mdia.rs +++ b/src/mp4box/mdia.rs @@ -54,6 +54,11 @@ impl ReadBox<&mut R> for MdiaBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "mdia box contains a box with a larger size than it", + )); + } match name { BoxType::MdhdBox => { diff --git a/src/mp4box/minf.rs b/src/mp4box/minf.rs index c8ecf72..5ea853b 100644 --- a/src/mp4box/minf.rs +++ b/src/mp4box/minf.rs @@ -69,6 +69,11 @@ impl ReadBox<&mut R> for MinfBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "minf box contains a box with a larger size than it", + )); + } match name { BoxType::VmhdBox => { diff --git a/src/mp4box/moof.rs b/src/mp4box/moof.rs index ab24bee..20c3565 100644 --- a/src/mp4box/moof.rs +++ b/src/mp4box/moof.rs @@ -58,6 +58,11 @@ impl ReadBox<&mut R> for MoofBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "moof box contains a box with a larger size than it", + )); + } match name { BoxType::MfhdBox => { diff --git a/src/mp4box/moov.rs b/src/mp4box/moov.rs index fe42ef5..ac19381 100644 --- a/src/mp4box/moov.rs +++ b/src/mp4box/moov.rs @@ -77,6 +77,11 @@ impl ReadBox<&mut R> for MoovBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "moov box contains a box with a larger size than it", + )); + } match name { BoxType::MvhdBox => { diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs index bc69fc6..e4d6a45 100644 --- a/src/mp4box/mp4a.rs +++ b/src/mp4box/mp4a.rs @@ -94,6 +94,11 @@ impl ReadBox<&mut R> for Mp4aBox { if current < start + size { let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "mp4a box contains a box with a larger size than it", + )); + } if name == BoxType::EsdsBox { esds = Some(EsdsBox::read_box(reader, s)?); diff --git a/src/mp4box/mvex.rs b/src/mp4box/mvex.rs index da61b95..8be683b 100644 --- a/src/mp4box/mvex.rs +++ b/src/mp4box/mvex.rs @@ -52,6 +52,11 @@ impl ReadBox<&mut R> for MvexBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "mvex box contains a box with a larger size than it", + )); + } match name { BoxType::MehdBox => { diff --git a/src/mp4box/stbl.rs b/src/mp4box/stbl.rs index 9656f4b..ef8433b 100644 --- a/src/mp4box/stbl.rs +++ b/src/mp4box/stbl.rs @@ -92,6 +92,11 @@ impl ReadBox<&mut R> for StblBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "stbl box contains a box with a larger size than it", + )); + } match name { BoxType::StsdBox => { diff --git a/src/mp4box/stco.rs b/src/mp4box/stco.rs index 2f252f5..a00da8f 100644 --- a/src/mp4box/stco.rs +++ b/src/mp4box/stco.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -48,7 +49,20 @@ impl ReadBox<&mut R> for StcoBox { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; + let other_size = size_of::(); // entry_count + let entry_size = size_of::(); // chunk_offset let entry_count = reader.read_u32::()?; + if u64::from(entry_count) + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + / entry_size as u64 + { + return Err(Error::InvalidData( + "stco entry_count indicates more entries than could fit in the box", + )); + } let mut entries = Vec::with_capacity(entry_count as usize); for _i in 0..entry_count { let chunk_offset = reader.read_u32::()?; diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs index 53d45c5..e5b444e 100644 --- a/src/mp4box/stsc.rs +++ b/src/mp4box/stsc.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -56,7 +57,20 @@ impl ReadBox<&mut R> for StscBox { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; + let other_size = size_of::(); // entry_count + let entry_size = size_of::() + size_of::() + size_of::(); // first_chunk + samples_per_chunk + sample_description_index let entry_count = reader.read_u32::()?; + if u64::from(entry_count) + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + / entry_size as u64 + { + return Err(Error::InvalidData( + "stsc entry_count indicates more entries than could fit in the box", + )); + } let mut entries = Vec::with_capacity(entry_count as usize); for _ in 0..entry_count { let entry = StscEntry { @@ -77,7 +91,14 @@ impl ReadBox<&mut R> for StscBox { }; if i < entry_count - 1 { let next_entry = entries.get(i as usize + 1).unwrap(); - sample_id += (next_entry.first_chunk - first_chunk) * samples_per_chunk; + sample_id = next_entry + .first_chunk + .checked_sub(first_chunk) + .and_then(|n| n.checked_mul(samples_per_chunk)) + .and_then(|n| n.checked_add(sample_id)) + .ok_or(Error::InvalidData( + "attempt to calculate stsc sample_id with overflow", + ))?; } } diff --git a/src/mp4box/stsd.rs b/src/mp4box/stsd.rs index 8387bbb..af947c6 100644 --- a/src/mp4box/stsd.rs +++ b/src/mp4box/stsd.rs @@ -85,6 +85,11 @@ impl ReadBox<&mut R> for StsdBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "stsd box contains a box with a larger size than it", + )); + } match name { BoxType::Avc1Box => { diff --git a/src/mp4box/stss.rs b/src/mp4box/stss.rs index 775131b..dd9e552 100644 --- a/src/mp4box/stss.rs +++ b/src/mp4box/stss.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -48,7 +49,20 @@ impl ReadBox<&mut R> for StssBox { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; + let other_size = size_of::(); // entry_count + let entry_size = size_of::(); // sample_number let entry_count = reader.read_u32::()?; + if u64::from(entry_count) + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + / entry_size as u64 + { + return Err(Error::InvalidData( + "stss entry_count indicates more entries than could fit in the box", + )); + } let mut entries = Vec::with_capacity(entry_count as usize); for _i in 0..entry_count { let sample_number = reader.read_u32::()?; diff --git a/src/mp4box/stsz.rs b/src/mp4box/stsz.rs index bd0e184..b07e765 100644 --- a/src/mp4box/stsz.rs +++ b/src/mp4box/stsz.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -55,10 +56,28 @@ impl ReadBox<&mut R> for StszBox { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; + let other_size = size_of::() + size_of::(); // sample_size + sample_count let sample_size = reader.read_u32::()?; + let stsz_item_size = if sample_size == 0 { + size_of::() // entry_size + } else { + 0 + }; let sample_count = reader.read_u32::()?; - let mut sample_sizes = Vec::with_capacity(sample_count as usize); + let mut sample_sizes = Vec::new(); if sample_size == 0 { + if u64::from(sample_count) + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + / stsz_item_size as u64 + { + return Err(Error::InvalidData( + "stsz sample_count indicates more values than could fit in the box", + )); + } + sample_sizes.reserve(sample_count as usize); for _ in 0..sample_count { let sample_number = reader.read_u32::()?; sample_sizes.push(sample_number); diff --git a/src/mp4box/stts.rs b/src/mp4box/stts.rs index ea84692..82de6c5 100644 --- a/src/mp4box/stts.rs +++ b/src/mp4box/stts.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -54,7 +55,20 @@ impl ReadBox<&mut R> for SttsBox { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; + let other_size = size_of::(); // entry_count + let entry_size = size_of::() + size_of::(); // sample_count + sample_delta let entry_count = reader.read_u32::()?; + if u64::from(entry_count) + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + / entry_size as u64 + { + return Err(Error::InvalidData( + "stts entry_count indicates more entries than could fit in the box", + )); + } let mut entries = Vec::with_capacity(entry_count as usize); for _i in 0..entry_count { let entry = SttsEntry { diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs index 8c01dc5..51f812d 100644 --- a/src/mp4box/traf.rs +++ b/src/mp4box/traf.rs @@ -59,6 +59,11 @@ impl ReadBox<&mut R> for TrafBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "traf box contains a box with a larger size than it", + )); + } match name { BoxType::TfhdBox => { diff --git a/src/mp4box/trak.rs b/src/mp4box/trak.rs index 9a83229..e8ae760 100644 --- a/src/mp4box/trak.rs +++ b/src/mp4box/trak.rs @@ -68,6 +68,11 @@ impl ReadBox<&mut R> for TrakBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "trak box contains a box with a larger size than it", + )); + } match name { BoxType::TkhdBox => { diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs index 7a8278d..efbb2b0 100644 --- a/src/mp4box/trun.rs +++ b/src/mp4box/trun.rs @@ -1,6 +1,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::Serialize; use std::io::{Read, Seek, Write}; +use std::mem::size_of; use crate::mp4box::*; @@ -83,6 +84,15 @@ impl ReadBox<&mut R> for TrunBox { let (version, flags) = read_box_header_ext(reader)?; + let header_size = HEADER_SIZE + HEADER_EXT_SIZE; + let other_size = size_of::() // sample_count + + if TrunBox::FLAG_DATA_OFFSET & flags > 0 { size_of::() } else { 0 } // data_offset + + if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & flags > 0 { size_of::() } else { 0 }; // first_sample_flags + let sample_size = if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 { size_of::() } else { 0 } // sample_duration + + if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 { size_of::() } else { 0 } // sample_size + + if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 { size_of::() } else { 0 } // sample_flags + + if TrunBox::FLAG_SAMPLE_CTS & flags > 0 { size_of::() } else { 0 }; // sample_composition_time_offset + let sample_count = reader.read_u32::()?; let data_offset = if TrunBox::FLAG_DATA_OFFSET & flags > 0 { @@ -97,10 +107,32 @@ impl ReadBox<&mut R> for TrunBox { None }; - let mut sample_durations = Vec::with_capacity(sample_count as usize); - let mut sample_sizes = Vec::with_capacity(sample_count as usize); - let mut sample_flags = Vec::with_capacity(sample_count as usize); - let mut sample_cts = Vec::with_capacity(sample_count as usize); + let mut sample_durations = Vec::new(); + let mut sample_sizes = Vec::new(); + let mut sample_flags = Vec::new(); + let mut sample_cts = Vec::new(); + if u64::from(sample_count) * sample_size as u64 + > size + .saturating_sub(header_size) + .saturating_sub(other_size as u64) + { + return Err(Error::InvalidData( + "trun sample_count indicates more values than could fit in the box", + )); + } + if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 { + sample_durations.reserve(sample_count as usize); + } + if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 { + sample_sizes.reserve(sample_count as usize); + } + if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 { + sample_flags.reserve(sample_count as usize); + } + if TrunBox::FLAG_SAMPLE_CTS & flags > 0 { + sample_cts.reserve(sample_count as usize); + } + for _ in 0..sample_count { if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 { let duration = reader.read_u32::()?; diff --git a/src/mp4box/udta.rs b/src/mp4box/udta.rs index 64bad5c..9daec17 100644 --- a/src/mp4box/udta.rs +++ b/src/mp4box/udta.rs @@ -55,6 +55,11 @@ impl ReadBox<&mut R> for UdtaBox { // Get box header. let header = BoxHeader::read(reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "udta box contains a box with a larger size than it", + )); + } match name { BoxType::MetaBox => { diff --git a/src/mp4box/vp09.rs b/src/mp4box/vp09.rs index 0e34146..0f88dd1 100644 --- a/src/mp4box/vp09.rs +++ b/src/mp4box/vp09.rs @@ -121,6 +121,11 @@ impl ReadBox<&mut R> for Vp09Box { let vpcc = { let header = BoxHeader::read(reader)?; + if header.size > size { + return Err(Error::InvalidData( + "vp09 box contains a box with a larger size than it", + )); + } VpccBox::read_box(reader, header.size)? }; diff --git a/src/reader.rs b/src/reader.rs index 38fde46..5a39eeb 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -31,6 +31,11 @@ impl Mp4Reader { // Get box header. let header = BoxHeader::read(&mut reader)?; let BoxHeader { name, size: s } = header; + if s > size { + return Err(Error::InvalidData( + "file contains a box with a larger size than it", + )); + } // Break if size zero BoxHeader, which can result in dead-loop. if s == 0 { diff --git a/src/track.rs b/src/track.rs index e9b4397..472ca1d 100644 --- a/src/track.rs +++ b/src/track.rs @@ -234,7 +234,9 @@ impl Mp4Track { let mut sample_count = 0u32; for traf in self.trafs.iter() { if let Some(ref trun) = traf.trun { - sample_count += trun.sample_count; + sample_count = sample_count + .checked_add(trun.sample_count) + .expect("attempt to sum trun sample_count with overflow"); } } sample_count @@ -342,12 +344,18 @@ impl Mp4Track { fn ctts_index(&self, sample_id: u32) -> Result<(usize, u32)> { let ctts = self.trak.mdia.minf.stbl.ctts.as_ref().unwrap(); - let mut sample_count = 1; + let mut sample_count: u32 = 1; for (i, entry) in ctts.entries.iter().enumerate() { - if sample_id < sample_count + entry.sample_count { + let next_sample_count = + sample_count + .checked_add(entry.sample_count) + .ok_or(Error::InvalidData( + "attempt to sum ctts entries sample_count with overflow", + ))?; + if sample_id < next_sample_count { return Ok((i, sample_count)); } - sample_count += entry.sample_count; + sample_count = next_sample_count; } Err(Error::EntryInStblNotFound( @@ -367,7 +375,9 @@ impl Mp4Track { if sample_count > (global_idx - offset) { return Some((traf_idx, (global_idx - offset) as _)); } - offset += sample_count; + offset = offset + .checked_add(sample_count) + .expect("attempt to sum trun sample_count with overflow"); } } None @@ -441,7 +451,13 @@ impl Mp4Track { let first_sample = stsc_entry.first_sample; let samples_per_chunk = stsc_entry.samples_per_chunk; - let chunk_id = first_chunk + (sample_id - first_sample) / samples_per_chunk; + let chunk_id = sample_id + .checked_sub(first_sample) + .map(|n| n / samples_per_chunk) + .and_then(|n| n.checked_add(first_chunk)) + .ok_or(Error::InvalidData( + "attempt to calculate stsc chunk_id with overflow", + ))?; let chunk_offset = self.chunk_offset(chunk_id)?; @@ -459,7 +475,7 @@ impl Mp4Track { fn sample_time(&self, sample_id: u32) -> Result<(u64, u32)> { let stts = &self.trak.mdia.minf.stbl.stts; - let mut sample_count = 1; + let mut sample_count: u32 = 1; let mut elapsed = 0; if !self.trafs.is_empty() { @@ -467,13 +483,19 @@ impl Mp4Track { Ok((start_time, self.default_sample_duration)) } else { for entry in stts.entries.iter() { - if sample_id < sample_count + entry.sample_count { + let new_sample_count = + sample_count + .checked_add(entry.sample_count) + .ok_or(Error::InvalidData( + "attempt to sum stts entries sample_count with overflow", + ))?; + if sample_id < new_sample_count { let start_time = (sample_id - sample_count) as u64 * entry.sample_delta as u64 + elapsed; return Ok((start_time, entry.sample_delta)); } - sample_count += entry.sample_count; + sample_count = new_sample_count; elapsed += entry.sample_count as u64 * entry.sample_delta as u64; } @@ -518,7 +540,11 @@ impl Mp4Track { Err(Error::EntryInStblNotFound(_, _, _)) => return Ok(None), Err(err) => return Err(err), }; - let sample_size = self.sample_size(sample_id).unwrap(); + let sample_size = match self.sample_size(sample_id) { + Ok(size) => size, + Err(Error::EntryInStblNotFound(_, _, _)) => return Ok(None), + Err(err) => return Err(err), + }; let mut buffer = vec![0x0u8; sample_size as usize]; reader.seek(SeekFrom::Start(sample_offset))?;