Validation¶
apm-partition-forensic parses untrusted Apple Partition Map structures from
potentially compromised disk images. Correctness for forensic tooling is
established against independent oracles (a different tool, or a different code
path, that already decodes the same bytes correctly) on real corpora with
known ground truth — never against fixtures we hand-encoded and then graded
ourselves.
This page records exactly which oracle and which corpus back each capability, so
the claim is independently re-checkable. The partition-map reader is now
Tier 1: two independent decoders (mmls -t mac and pdisk -dump) re-decode the
same committed bytes and the test reconciles our parse against their actual output.
The anomaly auditor remains Tier 3 — its detectors are still exercised only by
hand-built fixtures, and this page says so plainly rather than implying a stronger
guarantee.
How to read the evidence tiers¶
Each validation below is tagged with the trustworthiness of its check, not whether the data is "synthetic":
- Tier 1 — an independent third party authored the artifact and the answer key, or it is real-world data decoded by an independent tool. The strongest claim.
- Tier 2 — real engine output whose ground truth is derivable from the documented construction, or confirmed by an independent code path on real data. Genuinely checked, but we chose the scenario.
- Tier 3 — fixture and expected answer both authored here, nothing independent vouching. Used only for per-branch coverage, never as a correctness claim: a self-consistent round trip proves internal consistency, not correctness against real-world bytes.
Independent oracles¶
The partition-map reader is cross-checked by two independent decoders, each a
separate codebase that re-decodes the same committed bytes the crate parses.
forensic/tests/real_apm_oracle.rs runs them at test time (env-gated: a missing
binary skips that oracle cleanly) and asserts our parse matches their actual
reported entry count, type, start block, and block count.
| Oracle | Independent of us? | Validates | Tier | Status |
|---|---|---|---|---|
mmls -t mac (The Sleuth Kit 4.12.1) |
Yes — independent C codebase | entry count, type, start block, block count over apm_map_32k.bin |
1 | Wired in (crate_matches_mmls_oracle) |
pdisk -dump (Apple, v0.9a2) |
Yes — Apple's canonical APM editor | entry count, type, name, start block, block count over apm_map_32k.bin |
1 | Wired in (crate_matches_pdisk_oracle) |
The two oracles are additionally asserted to agree with each other on geometry
(oracles_agree_on_geometry), so the differential compares like with like
independent of this crate.
mmls(mmls -t mac <image>) — emits the APM partition table (slot, start, length, description) from an independent C codebase; the natural differential for partition bounds, overlap, and unmapped-gap findings.pdisk(pdisk -dump <image>) — prints DDM block size, everypmPartName/pmPartType, andpmPyPartStart/pmPartBlkCnt. The canonical APM reference tool. (It warns on stderr about unreadable data blocks beyond the 32 KiB head; the partition-map decode on stdout is unaffected.)
Still-available oracles not yet wired in: mac-fdisk -l (Linux util-mac) and
hdiutil pmap (macOS, reads back an existing image — distinct from using
hdiutil create to produce the fixture). Either would add a third independent
cross-check.
Independent test corpora¶
| Corpus | Source | Used for | License / redistribution |
|---|---|---|---|
apm_map_32k.bin (first 32 KiB of an 8 MiB hdiutil create -size 8m -layout SPUD -fs HFS+ image) |
Real Apple hdiutil output on macOS (DDM + Apple_partition_map + Apple_HFS, block size 512) |
Tier-1 differential vs mmls -t mac + pdisk -dump (entry count, type, name, start, count) |
Self-minted; committed (tests/data/apm_map_32k.bin) |
apm_map.bin (first 2 KiB of an hdiutil create -layout SPUD image) |
Real Apple hdiutil output on macOS (DDM + Apple_partition_map + Apple_HFS, block size 512) |
Reader/auditor real-data check in map.rs / analyse_tests.rs (block size, entry count, type names, HFS start block) |
Self-minted; committed (tests/data/apm_map.bin) |
Both fixtures are genuine Apple hdiutil output, so the on-disk layout is real
(not a byte-pattern we invented). The apm_map_32k.bin parse is now graded by two
independent decoders re-reading the same bytes (Tier 1) — 32 KiB is the
smallest head both mmls and pdisk fully decode (mmls probes the HFS partition's
start area at sector 64; pdisk decodes the map from the first 2 KiB). The older
apm_map.bin is still consumed by the reader/auditor real-data tests; its
expected values there were authored here, so on its own it is Tier 2. There is
no third-party APM corpus (e.g. a CTF image, a NIST CFReDS Mac image, or a
published forensic sample) in the suite yet; adding one with an externally-authored
answer key would be a further independent cross-check.
Provenance note: per-file provenance (source, verbatim generator command, MD5/ SHA256, consumers) lives in the repo's
tests/data/README.md; the fleet-wide machine index isissen/docs/corpus-catalog.md.
Per-capability validation¶
Partition-map reader (DDM + entries) — Tier 1¶
forensic/tests/real_apm_oracle.rs re-decodes the committed apm_map_32k.bin
with two independent tools and asserts the crate's parse matches each oracle's
actual reported values (never values this crate computed):
crate_matches_mmls_oracle— runsmmls -t mac(The Sleuth Kit), parses its partition rows, and reconciles entry count, type, start block, and block count againstapm::parse.crate_matches_pdisk_oracle— runspdisk -dump(Apple), parses its rows, and reconciles the same fields.oracles_agree_on_geometry— assertsmmlsandpdiskagree with each other, guarding the differential independent of this crate.
The reconciled ground truth (both oracles concur): block size 512, two entries —
Apple_partition_map (start block 1, 63 blocks) and Apple_HFS (name
disk image, start block 64, 16320 blocks). Each test is env-gated: a host
without that oracle binary skips the test cleanly. Because an independent codebase
authored the answer key by re-decoding the same bytes, this is Tier 1.
The original forensic/tests/map.rs reader assertions over apm_map.bin remain as
real-data regression checks (their expected values are authored here, so on their
own those are Tier 2):
parses_real_apple_partition_map— block size 512, exactly two entries,Apple_partition_mapthenApple_HFS, HFS nameddisk imagestarting at block 64.finds_hfs_partition—hfs_partition()locates theApple_HFSslice.non_apm_is_none— non-APM input (zeroed and too-short buffers) parses toNone, never a false-positive map.
Anomaly auditor (severity-graded findings) — Tier 3¶
The anomaly detectors —
APM-MAP-COUNT, APM-NO-MAP-ENTRY, APM-PART-OVERLAP, APM-PART-OOB,
APM-PART-RESIDUAL, APM-UNMAPPED, APM-PART-ZEROLEN, APM-PART-UNKNOWN —
are exercised by hand-built partition tables in
forensic/tests/analyse_tests.rs (the ent(...) helper constructs each scenario):
- one finding per code (
map_count_mismatch_flagged,missing_partition_map_self_entry_flagged,overlapping_partitions_flagged,out_of_bounds_flagged,residual_entry_flagged,unmapped_region_between_partitions_flagged,zero_length_partition_flagged,unknown_partition_type_flagged); - clean-input negatives (
well_formed_synthetic_is_clean, andreal_apm_is_cleanover the realapm_map.bin); - canonical-
Findingconversion and block-location evidence (forensic/tests/canonical_finding_tests.rs); - error-path coverage (
forensic/tests/error_tests.rs).
These fixtures are authored here and graded here — Tier 3: they prove each
detector fires on a constructed instance and stays silent on a clean one, which is
correct per-branch coverage, not a correctness claim against adversarial
real-world maps. The honest gap is a real APM carrying a naturally-occurring
anomaly (e.g. a wiped/residual entry from a real wipe, an overlap from a real
corruption) cross-checked against mmls/pdisk. There is no such corpus today.
Robustness — never panic, never over-read¶
forensic/tests/proptests.rs drives parse and analyse with property-based
random input (invariant: must not panic; end_block_never_precedes_start,
byte_and_reader_apis_agree). Two cargo-fuzz targets back this:
fuzz/fuzz_targets/fuzz_parse.rs (the reader) and
fuzz/fuzz_targets/fuzz_forensic.rs (the full analyse audit pipeline), each with
the "must not panic" invariant. Production code is #![forbid(unsafe_code)] and
denies clippy::unwrap_used / clippy::expect_used; integers are read through
bounds-checked helpers that return 0 on a short slice, and the entry count is
capped (MAX_PARTITIONS) against a corrupt map. This is a real robustness
guarantee (independent of the correctness tier above).
Reproducing the validation¶
All tests are committed and always-on (no large external image is required):
# Tier-1 differential: crate parse vs mmls -t mac AND pdisk -dump on the same bytes
# (env-gated; skips an oracle cleanly if its binary is absent)
cargo test -p apm-partition-forensic --test real_apm_oracle -- --nocapture
# Reader vs the real hdiutil-created APM (committed fixture)
cargo test -p apm-partition-forensic --test map
# Anomaly auditor: one test per finding code + clean negatives
cargo test -p apm-partition-forensic --test analyse_tests
# Canonical Finding conversion + error paths + property tests
cargo test -p apm-partition-forensic --test canonical_finding_tests \
--test error_tests \
--test proptests
# Whole workspace
cargo test --workspace
# Fuzz (must-not-panic) — requires the nightly cargo-fuzz toolchain
cargo +nightly fuzz run fuzz_parse
cargo +nightly fuzz run fuzz_forensic
To regenerate the committed Tier-1 fixture from scratch and re-confirm the oracle agreement on a freshly minted APM:
# Produce a real APM image (macOS) and slice the 32 KiB head both oracles decode
hdiutil create -size 8m -layout SPUD -fs HFS+ -volname OracleTest /tmp/apm_oracle
dd if=/tmp/apm_oracle.dmg of=tests/data/apm_map_32k.bin bs=1024 count=32
# Independent decode of the same bytes (the answer key the differential reconciles)
pdisk tests/data/apm_map_32k.bin -dump # Apple partition editor
mmls -t mac tests/data/apm_map_32k.bin # The Sleuth Kit
Coverage & fuzzing as backstops¶
100% line coverage is enforced in CI (cargo llvm-cov --lib, failing on any
zero-hit line not annotated // cov:unreachable). Coverage is a regression
backstop that proves behavior is exercised — it is not the correctness claim. The
oracles are; and where they are absent (above), this page says so rather than
implying a stronger guarantee than the tests deliver.