Skip to content

Commit

Permalink
Define 4GB as default maximum valid size for tags, but allow overridi…
Browse files Browse the repository at this point in the history
…ng as needed
  • Loading branch information
austinleroy committed Feb 27, 2024
1 parent 5160c40 commit 32b27da
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ebml-iterable"
version = "0.6.0"
version = "0.6.1"
authors = ["Austin Blake <austinl3roy@gmail.com>"]
edition = "2018"
description = "This crate provides an iterator over EBML encoded data. The items provided by the iterator are Tags as defined in EBML. The iterator is spec-agnostic and requires a specification implementing specific traits to read files. Typically, you would only use this crate to implement a custom specification - most often you would prefer a crate providing an existing specification, like `webm-iterable`."
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ binary version of XML. It's used for container formats like [WebM][webm] or
```Cargo.toml
[dependencies]
ebml-iterable = "0.6.0"
ebml-iterable = "0.6.1"
```

# Usage
Expand Down
28 changes: 27 additions & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,27 @@ pub mod tag_iterator {
///
size: usize
},

///
/// An error indicating the reader found a tag with an invalid size.
///
InvalidTagSize {

///
/// The position of the element.
///
position: usize,

///
/// The id of the tag that was found.
///
tag_id: u64,

///
/// The size of the tag that was found.
///
size: usize
},
}

impl fmt::Display for CorruptedFileError {
Expand All @@ -141,7 +162,12 @@ pub mod tag_iterator {
position,
tag_id,
size : _
} => write!(f, "Found an oversized tag [0x{tag_id:x?}] at position {position}")
} => write!(f, "Found an oversized tag [0x{tag_id:x?}] at position {position}"),
CorruptedFileError::InvalidTagSize {
position,
tag_id,
size,
} => write!(f, "Found an oversized tag [0x{tag_id:x?}] at position {position} with size {size}. Max supported size is 8GB."),
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions src/tag_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub struct TagIterator<R: Read, TSpec>
source: R,
tag_ids_to_buffer: HashSet<u64>,
allowed_errors: u8,
max_allowed_tag_size: Option<usize>,

buffer: Box<[u8]>,
buffer_offset: Option<usize>,
Expand Down Expand Up @@ -93,6 +94,7 @@ impl<R: Read, TSpec> TagIterator<R, TSpec>
source,
tag_ids_to_buffer: tags_to_buffer.iter().map(|tag| tag.get_id()).collect(),
allowed_errors: 0,
max_allowed_tag_size: Some(4 * usize::pow(1000, 3)), // 4GB
buffer: buffer.into_boxed_slice(),
buffered_byte_length: 0,
buffer_offset: None,
Expand Down Expand Up @@ -125,6 +127,15 @@ impl<R: Read, TSpec> TagIterator<R, TSpec>
});
}

///
/// Configures the maximum size a tag is allowed to be before the iterator considers it invalid.
///
/// By default (as of v0.6.1), the iterator will throw an [`CorruptedFileError::InvalidTagSize`] error if it comes across any tags that declare their data to be more than 4GB. This method can be used to change (and optionally remove) this behavior. Note that increasing this size can potentially result in massive allocations, causing delays and panics.
///
pub fn set_max_allowable_tag_size(&mut self, size: Option<usize>) {
self.max_allowed_tag_size = size;
}

///
/// Instructs the iterator to attempt to recover after reaching corrupted file data.
///
Expand Down Expand Up @@ -307,6 +318,12 @@ impl<R: Read, TSpec> TagIterator<R, TSpec>
return Err(TagIteratorError::CorruptedFileData(CorruptedFileError::OversizedChildElement{ position: self.current_offset(), tag_id, size: size.value()}));
}

if let Some(max_size) = self.max_allowed_tag_size {
if size.is_known() && size.value() > max_size {
return Err(TagIteratorError::CorruptedFileData(CorruptedFileError::InvalidTagSize { position: self.current_offset(), tag_id, size: size.value() }));
}
}

Ok((tag_id, spec_tag_type, size, header_len))
}

Expand Down
44 changes: 43 additions & 1 deletion tests/corrupt_data_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub mod corrupt_data_tests {
use ebml_iterable::error::{TagIteratorError, CorruptedFileError};
use ebml_iterable::iterator::AllowableErrors;
use ebml_iterable::specs::Master;
use ebml_iterable::{TagIterator, TagWriter};
use ebml_iterable::{TagIterator, TagWriter, WriteOptions};
use std::io::Cursor;

use super::test_spec::TestSpec;
Expand Down Expand Up @@ -121,6 +121,48 @@ pub mod corrupt_data_tests {
reader.for_each(|t| assert!(t.is_ok()));
}

fn get_data_with_6_byte_tag() -> Cursor<Vec<u8>> {
let tags: Vec<TestSpec> = vec![
TestSpec::Segment(Master::Start),
TestSpec::Cluster(Master::Start),
TestSpec::Block(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06]),
TestSpec::Cluster(Master::End),
TestSpec::Segment(Master::End),
];

let mut dest = Cursor::new(Vec::new());
let mut writer = TagWriter::new(&mut dest);

for tag in tags.iter() {
if matches!(tag, TestSpec::Segment(_)) || matches!(tag, TestSpec::Cluster(_)) {
writer.write_advanced(tag, WriteOptions::is_unknown_sized_element()).expect("Test shouldn't error");
} else {
writer.write(tag).expect("Test shouldn't error");
}
}

// // Rewrite size of block element
// dest.get_mut()[25] = 0x09;
// dest.get_mut()[26] = 0x65;
// dest.get_mut()[27] = 0xa0;
// dest.get_mut()[28] = 0xbc;
// dest.get_mut()[29] = 0x00;

println!("dest {:x?}", dest);
dest.set_position(0);
dest
}

#[test]
pub fn error_on_oversized_tag() {
let mut cursor = get_data_with_6_byte_tag();
let mut reader: TagIterator<_, TestSpec> = TagIterator::new(&mut cursor, &[]);
reader.set_max_allowable_tag_size(Some(5));
assert!(reader.next().unwrap().is_ok());
assert!(reader.next().unwrap().is_ok());
assert!(matches!(reader.next().unwrap(), Err(TagIteratorError::CorruptedFileData(CorruptedFileError::InvalidTagSize{position: _, tag_id: _, size: _}))));
}

#[test]
pub fn recover_on_global_element() {
let tags: Vec<TestSpec> = vec![
Expand Down

0 comments on commit 32b27da

Please sign in to comment.