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:
parent
024c26ade7
commit
ab412b063b
|
@ -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>()?;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)?;
|
||||
|
||||
|
|
|
@ -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>()?;
|
||||
|
|
|
@ -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",
|
||||
))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>()?;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>()?;
|
||||
|
|
40
src/track.rs
40
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)
|
||||
.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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue