1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-06-02 13:39:54 +00:00

Fix several overflows in box and track processing

This commit is contained in:
Lilith Silvestris 2023-01-23 16:10:38 -08:00
parent 024c26ade7
commit ab412b063b
13 changed files with 116 additions and 21 deletions

View file

@ -49,6 +49,11 @@ impl<R: Read + Seek> ReadBox<&mut R> for Co64Box {
let (version, flags) = read_box_header_ext(reader)?;
let entry_count = reader.read_u32::<BigEndian>()?;
if u64::from(entry_count) > size.saturating_sub(4) / 8 {
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::<BigEndian>()?;

View file

@ -55,6 +55,11 @@ impl<R: Read + Seek> ReadBox<&mut R> for CttsBox {
let (version, flags) = read_box_header_ext(reader)?;
let entry_count = reader.read_u32::<BigEndian>()?;
if u64::from(entry_count) > size.saturating_sub(4) / 8 {
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 {

View file

@ -254,7 +254,7 @@ impl<R: Read + Seek> 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)?;

View file

@ -63,6 +63,13 @@ impl<R: Read + Seek> ReadBox<&mut R> for ElstBox {
let (version, flags) = read_box_header_ext(reader)?;
let entry_count = reader.read_u32::<BigEndian>()?;
let header_size = 4;
let entry_size = if version == 1 { 20 } else { 12 };
if u64::from(entry_count) > size.saturating_sub(header_size) / entry_size {
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 {

View file

@ -53,12 +53,12 @@ impl<R: Read + Seek> ReadBox<&mut R> for FtypBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;
let major = reader.read_u32::<BigEndian>()?;
let minor = reader.read_u32::<BigEndian>()?;
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::<BigEndian>()?;
let minor = reader.read_u32::<BigEndian>()?;
let mut brands = Vec::new();
for _ in 0..brand_count {

View file

@ -52,7 +52,9 @@ impl<R: Read + Seek> 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)?;

View file

@ -49,6 +49,11 @@ impl<R: Read + Seek> ReadBox<&mut R> for StcoBox {
let (version, flags) = read_box_header_ext(reader)?;
let entry_count = reader.read_u32::<BigEndian>()?;
if u64::from(entry_count) > size.saturating_sub(4) / 4 {
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::<BigEndian>()?;

View file

@ -57,6 +57,11 @@ impl<R: Read + Seek> ReadBox<&mut R> for StscBox {
let (version, flags) = read_box_header_ext(reader)?;
let entry_count = reader.read_u32::<BigEndian>()?;
if u64::from(entry_count) > size.saturating_sub(4) / 12 {
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 +82,14 @@ impl<R: Read + Seek> 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",
))?;
}
}

View file

@ -49,6 +49,11 @@ impl<R: Read + Seek> ReadBox<&mut R> for StssBox {
let (version, flags) = read_box_header_ext(reader)?;
let entry_count = reader.read_u32::<BigEndian>()?;
if u64::from(entry_count) > size.saturating_sub(4) / 4 {
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::<BigEndian>()?;

View file

@ -57,8 +57,14 @@ impl<R: Read + Seek> ReadBox<&mut R> for StszBox {
let sample_size = reader.read_u32::<BigEndian>()?;
let sample_count = reader.read_u32::<BigEndian>()?;
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(8) / 4 {
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::<BigEndian>()?;
sample_sizes.push(sample_number);

View file

@ -55,6 +55,11 @@ impl<R: Read + Seek> ReadBox<&mut R> for SttsBox {
let (version, flags) = read_box_header_ext(reader)?;
let entry_count = reader.read_u32::<BigEndian>()?;
if u64::from(entry_count) > size.saturating_sub(4) / 8 {
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 {

View file

@ -97,10 +97,31 @@ impl<R: Read + Seek> 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();
let header_size = ((0x0000ff & flags).count_ones() + 1) * 4;
let entry_size = (0x00ff00 & flags).count_ones() * 4;
if u64::from(sample_count) * u64::from(entry_size)
> size.saturating_sub(u64::from(header_size))
{
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::<BigEndian>()?;

View file

@ -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)
.and_then(|n| n.checked_add(first_chunk))
.map(|n| n / samples_per_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;
}