From f512bf3d09c502c818322a4b8e77e3f450473bad Mon Sep 17 00:00:00 2001 From: osobh Date: Sat, 26 Sep 2026 10:38:50 -0500 Subject: [PATCH] conformance: report a cache image libhdf5 cannot load where it does libhdf5 loads a metadata cache image when it first reads metadata (the root group), not at open, so for cve-2025-6269-1..4 and cve-2025-6516 (all corrupt images) h5py opens the file and fails on "/". The probe reported the image's error as an open error, which made those files our-errors; it now records it on the root object, where h5py reports it. File::open still refuses such a file outright: nothing in it can be read. Co-Authored-By: Claude Opus 5.5 (1M context) --- conformance/probe/src/main.rs | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/conformance/probe/src/main.rs b/conformance/probe/src/main.rs index c4cf524..9fa9929 100644 --- a/conformance/probe/src/main.rs +++ b/conformance/probe/src/main.rs @@ -712,18 +712,35 @@ fn main() { return; } }; - // libhdf5 decodes the superblock extension at open, and loads a - // metadata cache image over the file's own metadata. - let view = match guarded(|| { - clawhdf5_format::superblock_ext::metadata_view(hdf5, &sb).map_err(e) - }) { - Ok(v) => v, + // libhdf5 decodes the superblock extension at open (File::open does + // the same), and loads a metadata cache image over the file's own + // metadata. It loads the image only when it first reads metadata — the + // root group — so a file whose image it cannot load still opens and + // every object fails; File::open refuses such a file outright. The + // probe records the image's error where libhdf5 reports it. + use clawhdf5_format::superblock_ext; + let ext = match guarded(|| superblock_ext::read_superblock_extension(hdf5, &sb).map_err(e)) { + Ok(x) => x, Err(msg) => { top.insert("open_error".into(), Value::String(msg)); println!("{}", Value::Object(top)); return; } }; + let mut image_error = None; + let view = match ext.and_then(|x| x.cache_image) { + None => None, + Some(loc) => match guarded(|| { + superblock_ext::apply_cache_image(hdf5, loc, sb.offset_size, sb.length_size) + .map_err(e) + }) { + Ok(v) => Some(v), + Err(msg) => { + image_error = Some(msg); + None + } + }, + }; let hdf5: &[u8] = view.as_deref().unwrap_or(hdf5); top.insert("superblock_version".into(), json!(sb.version)); let ctx = Ctx { @@ -752,6 +769,9 @@ fn main() { let mut rec = Map::new(); rec.insert("path".into(), Value::String(p.clone())); let r = guarded(|| { + if let Some(msg) = &image_error { + return Err(msg.clone()); + } let h = ctx.header(addr)?; Ok(h) });