diff --git a/crates/ogg/src/lib.rs b/crates/ogg/src/lib.rs index 77c081d52..719c96698 100644 --- a/crates/ogg/src/lib.rs +++ b/crates/ogg/src/lib.rs @@ -415,6 +415,11 @@ impl CaptureScanner { } fn read_parts(src: &(impl ByteSource + ?Sized), parts: &[(u64, u32)]) -> Result> { + // Ranges come from a scan of some source; check them against this one before sizing a buffer. + let len = src.len(); + if parts.iter().any(|&(o, n)| o.checked_add(u64::from(n)).is_none_or(|end| end > len)) { + return Err(Error::Invalid("packet range lies outside the source".into())); + } let mut v = Vec::with_capacity(parts.iter().map(|p| p.1 as usize).sum()); for &(o, n) in parts { let a = v.len(); diff --git a/crates/ogg/src/tests.rs b/crates/ogg/src/tests.rs index 480c1cda2..8f9673089 100644 --- a/crates/ogg/src/tests.rs +++ b/crates/ogg/src/tests.rs @@ -274,3 +274,13 @@ fn a_budget_too_small_to_search_is_spent() { let f = opus_file(6, 312, 0); assert_eq!(scanner.find(&f, 0, f.len() as u64).unwrap(), None); } + +#[test] +fn read_packet_checks_its_ranges_against_the_source_before_allocating() { + let f = opus_file(10, 312, 500); + let o = open(&f).unwrap(); + let s = o.stream_of(Codec::Opus).unwrap(); + // The last packet lies past the end of a source cut short: an error, not a read of missing bytes. + let short = &f[..f.len() / 2]; + assert!(matches!(o.read_packet(&short, s, 9), Err(Error::Invalid(_)))); +} diff --git a/xtask/src/stats.rs b/xtask/src/stats.rs index f40b1300a..20cd5725f 100644 --- a/xtask/src/stats.rs +++ b/xtask/src/stats.rs @@ -18,7 +18,13 @@ fn walk(dir: &Path, c: &mut Counts) { let p = e.path(); let name = e.file_name(); let name = name.to_string_lossy(); - if p.is_dir() { + // `file_type` does not follow links, so a directory link is not walked (and aliases are + // not counted twice). + let Ok(kind) = e.file_type() else { continue }; + if kind.is_symlink() { + continue; + } + if kind.is_dir() { // Nested fuzz workspaces and build output are not part of the crate. if name != "target" && name != "fuzz" && !name.starts_with('.') { walk(&p, c);