fix(format): refuse object headers libhdf5 refuses to load

ObjectHeader::parse now checks each header message the way libhdf5's
H5O__chunk_deserialize does, and fails with InvalidObjectHeader (libhdf5's
own error text) instead of reading objects out of a corrupt header:

- v1: every message in chunk 0 is read (not just the prefix's count) and
  more messages than the prefix claims is "bad object header message
  count"; message sizes must be multiples of 8; leftover bytes are a gap,
  which only v2 allows; the prefix's chunk size must fit its count.
- v1 and v2: a message running past its chunk is an error (it used to end
  the chunk quietly, dropping it and everything after); contradictory
  message flags; a message of a class that cannot be shared flagged
  shared/shareable; a reference-count message in a v1 header; malformed
  continuation, reference-count and modification-time messages (libhdf5
  decodes these while loading the header).
- v2: unknown header status flags, max_compact < min_dense, a chunk 0
  smaller than a message header, a gap in a chunk that has NIL messages.

Conformance (cached corpus, tank): 569 -> 570 ok (h5stat_err_refcount.h5).
Objects libhdf5 refuses that clawhdf5 used to read: cve-2016-4332-mtime
(/dataset), cve-2016-4332-mtime-new, cve-2018-11204, cve-2018-13873,
cve-2024-32619, cve-2024-33873, cve-2024-33874, gh-4433-poc-08; seven more
CVE objects that already failed now fail with libhdf5's reason.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
osobh
2026-09-26 00:02:49 -05:00
co-authored by Claude Opus 5.5
parent bb78d70b99
commit f4dee1cd08
2 changed files with 504 additions and 130 deletions
+8
View File
@@ -201,6 +201,11 @@ pub enum FormatError {
DuplicateDatasetName(String),
/// Integer overflow in size computation (malformed data protection).
Overflow(String),
/// An object header that libhdf5 refuses to load (the reason is
/// libhdf5's own error text): a misaligned or overrunning message, a
/// wrong message count, contradictory message flags, a message of a
/// class that cannot be shared flagged shareable, …
InvalidObjectHeader(&'static str),
}
impl fmt::Display for FormatError {
@@ -445,6 +450,9 @@ impl fmt::Display for FormatError {
FormatError::Overflow(msg) => {
write!(f, "integer overflow: {msg}")
}
FormatError::InvalidObjectHeader(why) => {
write!(f, "corrupt object header: {why}")
}
}
}
}