mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-11-10 06:34:18 +00:00
MP4: Allow invalid atom sizes with ParsingMode::Relaxed
This commit is contained in:
parent
9b4cf83f2a
commit
15c1aed9bf
3 changed files with 47 additions and 17 deletions
|
@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- **Timestamp**: `Timestamp::parse` with empty inputs will return `None` when not using `ParsingMode::Strict` ([PR](https://github.com/Serial-ATA/lofty-rs/pull/416))
|
- **Timestamp**: `Timestamp::parse` with empty inputs will return `None` when not using `ParsingMode::Strict` ([PR](https://github.com/Serial-ATA/lofty-rs/pull/416))
|
||||||
|
- **MP4**: Atoms with sizes greater than the remaining file size will be ignored with `ParsingMode::Relaxed` ([PR](https://github.com/Serial-ATA/lofty-rs/pull/433))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- **Fuzzing** (Thanks [@qarmin](https://github.com/qarmin)!) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/TODO)):
|
- **Fuzzing** (Thanks [@qarmin](https://github.com/qarmin)!) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/TODO)):
|
||||||
|
|
|
@ -180,7 +180,14 @@ impl AtomInfo {
|
||||||
|
|
||||||
// `len` includes itself and the identifier
|
// `len` includes itself and the identifier
|
||||||
if (len - ATOM_HEADER_LEN) > reader_size {
|
if (len - ATOM_HEADER_LEN) > reader_size {
|
||||||
data.seek(SeekFrom::Current(-4))?;
|
log::warn!("Encountered an atom with an invalid length, stopping");
|
||||||
|
|
||||||
|
if parse_mode == ParsingMode::Relaxed {
|
||||||
|
// Seek to the end, as we cannot gather anything else from the file
|
||||||
|
data.seek(SeekFrom::End(0))?;
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
err!(SizeMismatch);
|
err!(SizeMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +211,14 @@ impl AtomInfo {
|
||||||
ident: atom_ident,
|
ident: atom_ident,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn header_size(&self) -> u64 {
|
||||||
|
if !self.extended {
|
||||||
|
return ATOM_HEADER_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATOM_HEADER_LEN + 8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_freeform<R>(
|
fn parse_freeform<R>(
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use crate::config::ParsingMode;
|
use crate::config::ParsingMode;
|
||||||
use crate::error::{LoftyError, Result};
|
use crate::error::{LoftyError, Result};
|
||||||
|
use crate::io::{FileLike, Length, Truncate};
|
||||||
|
use crate::macros::err;
|
||||||
use crate::mp4::atom_info::{AtomIdent, AtomInfo, IDENTIFIER_LEN};
|
use crate::mp4::atom_info::{AtomIdent, AtomInfo, IDENTIFIER_LEN};
|
||||||
use crate::mp4::read::skip_unneeded;
|
use crate::mp4::read::{meta_is_full, skip_unneeded};
|
||||||
|
|
||||||
use std::cell::{RefCell, RefMut};
|
use std::cell::{RefCell, RefMut};
|
||||||
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use std::ops::RangeBounds;
|
use std::ops::RangeBounds;
|
||||||
|
|
||||||
use crate::io::{FileLike, Length, Truncate};
|
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
|
|
||||||
/// A wrapper around [`AtomInfo`] that allows us to track all of the children of containers we deem important
|
/// A wrapper around [`AtomInfo`] that allows us to track all of the children of containers we deem important
|
||||||
|
@ -17,8 +18,10 @@ pub(super) struct ContextualAtom {
|
||||||
pub(crate) children: Vec<ContextualAtom>,
|
pub(crate) children: Vec<ContextualAtom>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const META_ATOM_IDENT: AtomIdent<'_> = AtomIdent::Fourcc(*b"meta");
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
const IMPORTANT_CONTAINERS: [[u8; 4]; 7] = [
|
const IMPORTANT_CONTAINERS: &[[u8; 4]] = &[
|
||||||
*b"moov",
|
*b"moov",
|
||||||
*b"udta",
|
*b"udta",
|
||||||
*b"moof",
|
*b"moof",
|
||||||
|
@ -44,26 +47,37 @@ impl ContextualAtom {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut children = Vec::new();
|
match info.ident {
|
||||||
|
AtomIdent::Fourcc(ident) if IMPORTANT_CONTAINERS.contains(&ident) => {},
|
||||||
let AtomIdent::Fourcc(fourcc) = info.ident else {
|
_ => {
|
||||||
*reader_len = reader_len.saturating_sub(info.len);
|
|
||||||
return Ok(Some(ContextualAtom { info, children }));
|
|
||||||
};
|
|
||||||
|
|
||||||
if !IMPORTANT_CONTAINERS.contains(&fourcc) {
|
|
||||||
*reader_len = reader_len.saturating_sub(info.len);
|
*reader_len = reader_len.saturating_sub(info.len);
|
||||||
|
|
||||||
// We don't care about the atom's contents
|
// We don't care about the atom's contents
|
||||||
skip_unneeded(reader, info.extended, info.len)?;
|
skip_unneeded(reader, info.extended, info.len)?;
|
||||||
return Ok(Some(ContextualAtom { info, children }));
|
return Ok(Some(ContextualAtom {
|
||||||
|
info,
|
||||||
|
children: Vec::new(),
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut len = info.len - info.header_size();
|
||||||
|
let mut children = Vec::new();
|
||||||
|
|
||||||
|
// See meta_is_full for details
|
||||||
|
if info.ident == META_ATOM_IDENT && meta_is_full(reader)? {
|
||||||
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut len = info.len - 8;
|
|
||||||
while let Some(child) = Self::read(reader, &mut len, parse_mode)? {
|
while let Some(child) = Self::read(reader, &mut len, parse_mode)? {
|
||||||
children.push(child);
|
children.push(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len != 0 {
|
||||||
|
// TODO: Print the container ident
|
||||||
|
err!(BadAtom("Unable to read entire container"));
|
||||||
|
}
|
||||||
|
|
||||||
*reader_len = reader_len.saturating_sub(info.len);
|
*reader_len = reader_len.saturating_sub(info.len);
|
||||||
// reader.seek(SeekFrom::Current(*reader_len as i64))?; // Skip any remaining bytes
|
// reader.seek(SeekFrom::Current(*reader_len as i64))?; // Skip any remaining bytes
|
||||||
Ok(Some(ContextualAtom { info, children }))
|
Ok(Some(ContextualAtom { info, children }))
|
||||||
|
|
Loading…
Reference in a new issue