craft-aaf: reject cyclic root mini-stream chains

* craft-aaf: reject cyclic root mini-stream chains
This commit is contained in:
Dylan M. Taylor authored and GitHub committed 2026-11-12 06:25:55 -05:00
1 parent 584d87f9e1
commit f759a35db8
3 files changed
+25

No files matched your search

+1
View File
@@ -377,6 +377,7 @@ const MAX_PATH_BYTES: usize = 64 << 20;
/// Parse the object tree of an AAF compound file (the root object).
pub(crate) fn read(bytes: &[u8]) -> Result<Obj, String> {
let cf = CompoundFile::open(bytes).map_err(|e| e.to_string())?;
cf.validate_root_chain().map_err(|e| e.to_string())?;
let mut paths = Vec::new();
if let Ok(rp) = cf.read_path("referenced properties")
&& rp.len() >= 7
+13
View File
@@ -424,6 +424,19 @@ impl<'a> CompoundFile<'a> {
self.entries.first().unwrap_or(&EMPTY)
}
/// Reject a cycle or invalid link anywhere in the root mini-stream sector chain.
/// Opening remains tolerant so other streams can still be salvaged.
pub fn validate_root_chain(&self) -> Result<()> {
let root = self.root();
if root.size > 0 {
if root.start == ENDOFCHAIN {
return Err(invalid("nonempty root mini stream has no sector chain"));
}
self.chain_ids(root.start, None)?;
}
Ok(())
}
pub fn entry(&self, id: usize) -> Option<&Entry> {
self.entries.get(id)
}
+11
View File
@@ -702,3 +702,14 @@ fn special_values_in_every_field_never_panic() {
}
}
}
#[test]
fn strict_root_validation_rejects_a_loop_beyond_declared_mini_stream() {
let data = pattern(100, 1);
let mut file = foreign_file(&[("Small", &data)]);
let root = dir_at(&file, 0);
let start = u32::from_le_bytes(file[root + 116..root + 120].try_into().unwrap());
put_u32(&mut file, 512 + start as usize * 4, start);
let cf = CompoundFile::open(&file).unwrap();
assert!(cf.validate_root_chain().is_err());
}