Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/mp4box/avc1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ impl<R: Read + Seek> ReadBox<&mut R> for Avc1Box {

let header = BoxHeader::read(reader)?;
let BoxHeader { name, size: s } = header;
if s > size {
Copy link
Member

@jessa0 jessa0 Feb 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we could be more precise here (and below), with:

if s > size.saturating_sub(reader.stream_position() - start) {

Do you think it's worth it to do so? Maybe not, since I think these checks are mostly to prevent crashes due to large allocations, right? In that case, maybe add comments explaining why the checks are imprecise.

This also makes me realize that pretty much every read_box should be doing:

let mut reader = reader.take(size - HEADER_SIZE);

so that they don't read past the end of the box. But I can file a bug (#4) for that to do in a separate PR (since this one is getting large).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I seem to remember that this/something else already effectively prevented that sort of box overrun? I'll take another look, though; if that's not the case, I'll open another PR for #4.

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)?;

Expand Down
14 changes: 14 additions & 0 deletions src/mp4box/co64.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand Down Expand Up @@ -48,7 +49,20 @@ impl<R: Read + Seek> 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::<u32>(); // entry_count
let entry_size = size_of::<u64>(); // chunk_offset
let entry_count = reader.read_u32::<BigEndian>()?;
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::<BigEndian>()?;
Expand Down
15 changes: 15 additions & 0 deletions src/mp4box/ctts.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand Down Expand Up @@ -54,7 +55,21 @@ impl<R: Read + Seek> 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::<BigEndian>()?;
let entry_size = size_of::<u32>() + size_of::<i32>(); // sample_count + sample_offset
// (sample_offset might be a u32, but the size is the same.)
let other_size = size_of::<i32>(); // 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 {
Expand Down
12 changes: 11 additions & 1 deletion src/mp4box/dinf.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 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 => {
Expand Down Expand Up @@ -156,6 +161,11 @@ impl<R: Read + Seek> 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 => {
Expand Down Expand Up @@ -254,7 +264,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
5 changes: 5 additions & 0 deletions src/mp4box/edts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ impl<R: Read + Seek> 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)?;
Expand Down
23 changes: 23 additions & 0 deletions src/mp4box/elst.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand Down Expand Up @@ -62,7 +63,29 @@ impl<R: Read + Seek> 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::<BigEndian>()?;
let other_size = size_of::<i32>(); // entry_count
let entry_size = {
let mut entry_size = 0;
entry_size += if version == 1 {
size_of::<u64>() + size_of::<i64>() // segment_duration + media_time
} else {
size_of::<u32>() + size_of::<i32>() // segment_duration + media_time
};
entry_size += size_of::<i16>() + size_of::<i16>(); // 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 {
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
4 changes: 3 additions & 1 deletion src/mp4box/hdlr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;

Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/hev1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ impl<R: Read + Seek> 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)?;

Expand Down
10 changes: 10 additions & 0 deletions src/mp4box/ilst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ impl<R: Read + Seek> 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 => {
Expand Down Expand Up @@ -71,6 +76,11 @@ impl<R: Read + Seek> 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 => {
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/mdia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ impl<R: Read + Seek> 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 => {
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ impl<R: Read + Seek> ReadBox<&mut R> for MetaBox {
// Get box header.
let header = BoxHeader::read(reader)?;
let BoxHeader { name, size: s } = header;
if s > size {
return Err(Error::InvalidData(
"meta box contains a box with a larger size than it",
));
}

match name {
BoxType::IlstBox => {
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/minf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ impl<R: Read + Seek> 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 => {
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/moof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ impl<R: Read + Seek> 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 => {
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/moov.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ impl<R: Read + Seek> 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 => {
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/mp4a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ impl<R: Read + Seek> 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)?);
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/mvex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ impl<R: Read + Seek> 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 => {
Expand Down
5 changes: 5 additions & 0 deletions src/mp4box/stbl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ impl<R: Read + Seek> 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 => {
Expand Down
14 changes: 14 additions & 0 deletions src/mp4box/stco.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand Down Expand Up @@ -48,7 +49,20 @@ impl<R: Read + Seek> 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::<u32>(); // entry_count
let entry_size = size_of::<u32>(); // chunk_offset
let entry_count = reader.read_u32::<BigEndian>()?;
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::<BigEndian>()?;
Expand Down
23 changes: 22 additions & 1 deletion src/mp4box/stsc.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand Down Expand Up @@ -56,7 +57,20 @@ impl<R: Read + Seek> 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::<u32>(); // entry_count
let entry_size = size_of::<u32>() + size_of::<u32>() + size_of::<u32>(); // first_chunk + samples_per_chunk + sample_description_index
let entry_count = reader.read_u32::<BigEndian>()?;
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 {
Expand All @@ -77,7 +91,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/stsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ impl<R: Read + Seek> 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 => {
Expand Down
Loading