From c3b3581b7e397748a34192c1e4a8224fd30452be Mon Sep 17 00:00:00 2001 From: Lilith Silvestris <120892488+oftheforest@users.noreply.github.com> Date: Mon, 23 Jan 2023 16:10:38 -0800 Subject: [PATCH 1/6] Fix several overflows in box and track processing --- src/mp4box/co64.rs | 5 +++++ src/mp4box/ctts.rs | 5 +++++ src/mp4box/dinf.rs | 2 +- src/mp4box/elst.rs | 7 +++++++ src/mp4box/ftyp.rs | 8 ++++---- src/mp4box/hdlr.rs | 4 +++- src/mp4box/stco.rs | 5 +++++ src/mp4box/stsc.rs | 14 +++++++++++++- src/mp4box/stss.rs | 5 +++++ src/mp4box/stsz.rs | 8 +++++++- src/mp4box/stts.rs | 5 +++++ src/mp4box/trun.rs | 29 +++++++++++++++++++++++++---- src/track.rs | 40 +++++++++++++++++++++++++++++++--------- 13 files changed, 116 insertions(+), 21 deletions(-) diff --git a/src/mp4box/co64.rs b/src/mp4box/co64.rs index a7ea68a8..e3bce1b7 100644 --- a/src/mp4box/co64.rs +++ b/src/mp4box/co64.rs @@ -49,6 +49,11 @@ impl ReadBox<&mut R> for Co64Box { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; + 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::()?; diff --git a/src/mp4box/ctts.rs b/src/mp4box/ctts.rs index f0ed0027..1107e236 100644 --- a/src/mp4box/ctts.rs +++ b/src/mp4box/ctts.rs @@ -55,6 +55,11 @@ impl ReadBox<&mut R> for CttsBox { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; + 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 { diff --git a/src/mp4box/dinf.rs b/src/mp4box/dinf.rs index 3d9a95b0..4c468e4f 100644 --- a/src/mp4box/dinf.rs +++ b/src/mp4box/dinf.rs @@ -254,7 +254,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/elst.rs b/src/mp4box/elst.rs index 1c489521..e647a43c 100644 --- a/src/mp4box/elst.rs +++ b/src/mp4box/elst.rs @@ -63,6 +63,13 @@ impl ReadBox<&mut R> for ElstBox { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; + 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 { diff --git a/src/mp4box/ftyp.rs b/src/mp4box/ftyp.rs index ba1358dd..789cd4ef 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 9fb03686..1ff559e0 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/stco.rs b/src/mp4box/stco.rs index 2f252f50..14919515 100644 --- a/src/mp4box/stco.rs +++ b/src/mp4box/stco.rs @@ -49,6 +49,11 @@ impl ReadBox<&mut R> for StcoBox { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; + 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::()?; diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs index 53d45c55..385e87d7 100644 --- a/src/mp4box/stsc.rs +++ b/src/mp4box/stsc.rs @@ -57,6 +57,11 @@ impl ReadBox<&mut R> for StscBox { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; + 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 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/stss.rs b/src/mp4box/stss.rs index 775131bd..3ff50b8d 100644 --- a/src/mp4box/stss.rs +++ b/src/mp4box/stss.rs @@ -49,6 +49,11 @@ impl ReadBox<&mut R> for StssBox { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; + 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::()?; diff --git a/src/mp4box/stsz.rs b/src/mp4box/stsz.rs index bd0e184f..8b3b9d59 100644 --- a/src/mp4box/stsz.rs +++ b/src/mp4box/stsz.rs @@ -57,8 +57,14 @@ impl ReadBox<&mut R> for StszBox { let sample_size = reader.read_u32::()?; 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(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::()?; sample_sizes.push(sample_number); diff --git a/src/mp4box/stts.rs b/src/mp4box/stts.rs index ea846920..a0762c14 100644 --- a/src/mp4box/stts.rs +++ b/src/mp4box/stts.rs @@ -55,6 +55,11 @@ impl ReadBox<&mut R> for SttsBox { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; + 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 { diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs index 7a8278dd..1c3b9921 100644 --- a/src/mp4box/trun.rs +++ b/src/mp4box/trun.rs @@ -97,10 +97,31 @@ 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(); + 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::()?; diff --git a/src/track.rs b/src/track.rs index ed8b12e4..fecbd258 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) + .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; } From 22ff38029dd184903eb79dbaac7d138b9461b959 Mon Sep 17 00:00:00 2001 From: Lilith Silvestris <120892488+oftheforest@users.noreply.github.com> Date: Wed, 25 Jan 2023 12:43:58 -0800 Subject: [PATCH 2/6] Use size_of::() instead of magic numbers --- src/mp4box/co64.rs | 5 ++++- src/mp4box/ctts.rs | 6 +++++- src/mp4box/elst.rs | 16 +++++++++++++--- src/mp4box/stco.rs | 5 ++++- src/mp4box/stsc.rs | 5 ++++- src/mp4box/stss.rs | 5 ++++- src/mp4box/stsz.rs | 11 ++++++++++- src/mp4box/stts.rs | 7 ++++++- src/mp4box/trun.rs | 16 ++++++++++++---- 9 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/mp4box/co64.rs b/src/mp4box/co64.rs index e3bce1b7..7fac6bce 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,8 +49,10 @@ impl ReadBox<&mut R> for Co64Box { let (version, flags) = read_box_header_ext(reader)?; + 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(4) / 8 { + if u64::from(entry_count) > 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", )); diff --git a/src/mp4box/ctts.rs b/src/mp4box/ctts.rs index 1107e236..3c96dd6c 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::*; @@ -55,7 +56,10 @@ impl ReadBox<&mut R> for CttsBox { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; - if u64::from(entry_count) > size.saturating_sub(4) / 8 { + 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(other_size as u64) / entry_size as u64 { return Err(Error::InvalidData( "ctts entry_count indicates more entries than could fit in the box", )); diff --git a/src/mp4box/elst.rs b/src/mp4box/elst.rs index e647a43c..dd611ddd 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::*; @@ -63,9 +64,18 @@ impl ReadBox<&mut R> for ElstBox { let (version, flags) = read_box_header_ext(reader)?; let entry_count = reader.read_u32::()?; - 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 { + 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(other_size as u64) / entry_size as u64 { return Err(Error::InvalidData( "elst entry_count indicates more entries than could fit in the box", )); diff --git a/src/mp4box/stco.rs b/src/mp4box/stco.rs index 14919515..64351479 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,8 +49,10 @@ impl ReadBox<&mut R> for StcoBox { let (version, flags) = read_box_header_ext(reader)?; + 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(4) / 4 { + if u64::from(entry_count) > 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", )); diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs index 385e87d7..ada86d87 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,8 +57,10 @@ impl ReadBox<&mut R> for StscBox { let (version, flags) = read_box_header_ext(reader)?; + 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(4) / 12 { + if u64::from(entry_count) > 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", )); diff --git a/src/mp4box/stss.rs b/src/mp4box/stss.rs index 3ff50b8d..526ba88f 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,8 +49,10 @@ impl ReadBox<&mut R> for StssBox { let (version, flags) = read_box_header_ext(reader)?; + 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(4) / 4 { + if u64::from(entry_count) > 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", )); diff --git a/src/mp4box/stsz.rs b/src/mp4box/stsz.rs index 8b3b9d59..d083e2b2 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,11 +56,19 @@ impl ReadBox<&mut R> for StszBox { let (version, flags) = read_box_header_ext(reader)?; + 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::new(); if sample_size == 0 { - if u64::from(sample_count) > size.saturating_sub(8) / 4 { + if u64::from(sample_count) + > 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", )); diff --git a/src/mp4box/stts.rs b/src/mp4box/stts.rs index a0762c14..22ffc2b8 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,8 +55,12 @@ impl ReadBox<&mut R> for SttsBox { let (version, flags) = read_box_header_ext(reader)?; + 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(4) / 8 { + if u64::from(entry_count) + > 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", )); diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs index 1c3b9921..c7c1c47a 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,14 @@ impl ReadBox<&mut R> for TrunBox { let (version, flags) = read_box_header_ext(reader)?; + 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 { @@ -101,10 +110,8 @@ impl ReadBox<&mut R> for TrunBox { 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)) + if u64::from(sample_count) * sample_size as u64 + > size.saturating_sub(other_size as u64) { return Err(Error::InvalidData( "trun sample_count indicates more values than could fit in the box", @@ -122,6 +129,7 @@ impl ReadBox<&mut R> for TrunBox { 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::()?; From d7776def5751d19df595eaa3acc58b33236760a1 Mon Sep 17 00:00:00 2001 From: Lilith Silvestris <120892488+oftheforest@users.noreply.github.com> Date: Wed, 25 Jan 2023 15:20:11 -0800 Subject: [PATCH 3/6] Fix a panic in Mp4Track::read_sample() for one-past-the-end This appears to be a bug unmasked by other changes. read_sample() calls sample_offset() then sample_size(), and assumes that if the former returns Ok then the latter does as well. However, if the sample_id is one past the end, sample_offset() might succeed (it only checks samples _up to_ the given sample_id but not _including_ it) while sample_size() fails (because the sample doesn't exist). read_sample() will then panic. Fix this by duplicating the error propagation (that is currently done for sample_offset) for sample_size, instead of unwrapping. This is a cautious change that fixes the bug; alternatively, having sample_offset() call sample_size() on the given sample_id and propagate any error might also work. --- src/track.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/track.rs b/src/track.rs index fecbd258..074dadd4 100644 --- a/src/track.rs +++ b/src/track.rs @@ -540,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))?; From 57173ce2c493dcc731a88d21962cb95a90eef339 Mon Sep 17 00:00:00 2001 From: Lilith Silvestris <120892488+oftheforest@users.noreply.github.com> Date: Thu, 26 Jan 2023 14:51:10 -0800 Subject: [PATCH 4/6] Account for header size in box processing overflow fixes --- src/mp4box/co64.rs | 8 +++++++- src/mp4box/ctts.rs | 8 +++++++- src/mp4box/elst.rs | 8 +++++++- src/mp4box/stco.rs | 8 +++++++- src/mp4box/stsc.rs | 8 +++++++- src/mp4box/stss.rs | 8 +++++++- src/mp4box/stsz.rs | 6 +++++- src/mp4box/stts.rs | 6 +++++- src/mp4box/trun.rs | 5 ++++- 9 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/mp4box/co64.rs b/src/mp4box/co64.rs index 7fac6bce..978137e9 100644 --- a/src/mp4box/co64.rs +++ b/src/mp4box/co64.rs @@ -49,10 +49,16 @@ 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(other_size as u64) / entry_size as u64 { + 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", )); diff --git a/src/mp4box/ctts.rs b/src/mp4box/ctts.rs index 3c96dd6c..673e8c92 100644 --- a/src/mp4box/ctts.rs +++ b/src/mp4box/ctts.rs @@ -55,11 +55,17 @@ 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(other_size as u64) / entry_size as u64 { + 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", )); diff --git a/src/mp4box/elst.rs b/src/mp4box/elst.rs index dd611ddd..297fb63a 100644 --- a/src/mp4box/elst.rs +++ b/src/mp4box/elst.rs @@ -63,6 +63,7 @@ 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 = { @@ -75,7 +76,12 @@ impl ReadBox<&mut R> for ElstBox { entry_size += size_of::() + size_of::(); // media_rate_integer + media_rate_fraction entry_size }; - if u64::from(entry_count) > size.saturating_sub(other_size as u64) / entry_size as u64 { + 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", )); diff --git a/src/mp4box/stco.rs b/src/mp4box/stco.rs index 64351479..a00da8f9 100644 --- a/src/mp4box/stco.rs +++ b/src/mp4box/stco.rs @@ -49,10 +49,16 @@ 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(other_size as u64) / entry_size as u64 { + 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", )); diff --git a/src/mp4box/stsc.rs b/src/mp4box/stsc.rs index ada86d87..e5b444ef 100644 --- a/src/mp4box/stsc.rs +++ b/src/mp4box/stsc.rs @@ -57,10 +57,16 @@ 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(other_size as u64) / entry_size as u64 { + 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", )); diff --git a/src/mp4box/stss.rs b/src/mp4box/stss.rs index 526ba88f..dd9e552f 100644 --- a/src/mp4box/stss.rs +++ b/src/mp4box/stss.rs @@ -49,10 +49,16 @@ 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(other_size as u64) / entry_size as u64 { + 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", )); diff --git a/src/mp4box/stsz.rs b/src/mp4box/stsz.rs index d083e2b2..b07e7653 100644 --- a/src/mp4box/stsz.rs +++ b/src/mp4box/stsz.rs @@ -56,6 +56,7 @@ 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 { @@ -67,7 +68,10 @@ impl ReadBox<&mut R> for StszBox { let mut sample_sizes = Vec::new(); if sample_size == 0 { if u64::from(sample_count) - > size.saturating_sub(other_size as u64) / stsz_item_size as u64 + > 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", diff --git a/src/mp4box/stts.rs b/src/mp4box/stts.rs index 22ffc2b8..82de6c50 100644 --- a/src/mp4box/stts.rs +++ b/src/mp4box/stts.rs @@ -55,11 +55,15 @@ 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(other_size as u64) / entry_size as u64 + > 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", diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs index c7c1c47a..efbb2b09 100644 --- a/src/mp4box/trun.rs +++ b/src/mp4box/trun.rs @@ -84,6 +84,7 @@ 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 @@ -111,7 +112,9 @@ impl ReadBox<&mut R> for TrunBox { let mut sample_flags = Vec::new(); let mut sample_cts = Vec::new(); if u64::from(sample_count) * sample_size as u64 - > size.saturating_sub(other_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", From 990dd11a2e26834802a2377880622b516429ef2e Mon Sep 17 00:00:00 2001 From: Lilith Silvestris <120892488+oftheforest@users.noreply.github.com> Date: Fri, 3 Feb 2023 14:02:38 -0800 Subject: [PATCH 5/6] Ensure that boxes aren't bigger than their containers Together with the entry_count checks, this eliminates several OOMs when reading incorrect mp4 files. --- src/mp4box/avc1.rs | 5 +++++ src/mp4box/dinf.rs | 10 ++++++++++ src/mp4box/edts.rs | 5 +++++ src/mp4box/hev1.rs | 5 +++++ src/mp4box/ilst.rs | 10 ++++++++++ src/mp4box/mdia.rs | 5 +++++ src/mp4box/meta.rs | 5 +++++ src/mp4box/minf.rs | 5 +++++ src/mp4box/moof.rs | 5 +++++ src/mp4box/moov.rs | 5 +++++ src/mp4box/mp4a.rs | 5 +++++ src/mp4box/mvex.rs | 5 +++++ src/mp4box/stbl.rs | 5 +++++ src/mp4box/stsd.rs | 5 +++++ src/mp4box/traf.rs | 5 +++++ src/mp4box/trak.rs | 5 +++++ src/mp4box/udta.rs | 5 +++++ src/mp4box/vp09.rs | 5 +++++ src/reader.rs | 5 +++++ 19 files changed, 105 insertions(+) diff --git a/src/mp4box/avc1.rs b/src/mp4box/avc1.rs index 0e6d727b..71741228 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/dinf.rs b/src/mp4box/dinf.rs index 4c468e4f..cce67ad4 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 => { diff --git a/src/mp4box/edts.rs b/src/mp4box/edts.rs index 2d553571..9077bb17 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/hev1.rs b/src/mp4box/hev1.rs index b566aaa5..3a8cfead 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 9609c330..d2713027 100644 --- a/src/mp4box/ilst.rs +++ b/src/mp4box/ilst.rs @@ -25,6 +25,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 => { @@ -71,6 +76,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 c77b7673..914990ad 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/meta.rs b/src/mp4box/meta.rs index 49347a60..135dd438 100644 --- a/src/mp4box/meta.rs +++ b/src/mp4box/meta.rs @@ -28,6 +28,11 @@ impl 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 => { diff --git a/src/mp4box/minf.rs b/src/mp4box/minf.rs index 1551db8b..03689617 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 b9ab1d4c..6d037070 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 22b6276b..a2ff347d 100644 --- a/src/mp4box/moov.rs +++ b/src/mp4box/moov.rs @@ -66,6 +66,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 a7e0a95c..40de47cf 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 ec8c76f3..d68ec27a 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 e8b78b62..d824a4cc 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/stsd.rs b/src/mp4box/stsd.rs index 8387bbb0..af947c6c 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/traf.rs b/src/mp4box/traf.rs index 44d78f2d..49300ef0 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 c1e18452..56420f8c 100644 --- a/src/mp4box/trak.rs +++ b/src/mp4box/trak.rs @@ -63,6 +63,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/udta.rs b/src/mp4box/udta.rs index de5dd9bf..3b31fd41 100644 --- a/src/mp4box/udta.rs +++ b/src/mp4box/udta.rs @@ -23,6 +23,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 2e5fe57d..2459c132 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 ebb37218..a438308c 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -30,6 +30,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 { From a11ba617515374854a14e508a9a241abff35800f Mon Sep 17 00:00:00 2001 From: Lilith Silvestris <120892488+oftheforest@users.noreply.github.com> Date: Thu, 9 Feb 2023 14:27:51 -0800 Subject: [PATCH 6/6] Fix order of arithmetic operations This was due to an incorrect transcription when switching to checked arithmetic, and fixes a bug that could cause attempted lookups of the wrong chunk_id. --- src/track.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/track.rs b/src/track.rs index 074dadd4..c848725a 100644 --- a/src/track.rs +++ b/src/track.rs @@ -453,8 +453,8 @@ impl Mp4Track { let chunk_id = sample_id .checked_sub(first_sample) - .and_then(|n| n.checked_add(first_chunk)) .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", ))?;