Skip to content

Commit

Permalink
Fix several overflows in box and track processing
Browse files Browse the repository at this point in the history
  • Loading branch information
oftheforest committed Jan 24, 2023
1 parent 16c1b5d commit 47d26a0
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 21 deletions.
5 changes: 5 additions & 0 deletions src/mp4box/co64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>()?;
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/ctts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/mp4box/dinf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down
7 changes: 7 additions & 0 deletions src/mp4box/elst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions src/mp4box/ftyp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 5 additions & 1 deletion src/mp4box/hdlr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ 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)?;

Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/stco.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>()?;
Expand Down
14 changes: 13 additions & 1 deletion src/mp4box/stsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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",
))?;
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/stss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>()?;
Expand Down
8 changes: 7 additions & 1 deletion src/mp4box/stsz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/stts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
29 changes: 25 additions & 4 deletions src/mp4box/trun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
> size.saturating_sub(u64::from(header_size)) / u64::from(entry_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>()?;
Expand Down
40 changes: 31 additions & 9 deletions src/track.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand Down Expand Up @@ -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)?;

Expand All @@ -459,21 +475,27 @@ 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() {
let start_time = ((sample_id - 1) * self.default_sample_duration) as u64;
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;
}

Expand Down

0 comments on commit 47d26a0

Please sign in to comment.