DF-3012 / verdict.json
{ "finding_id": "DF-3012", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "Defect is code-certain: hammer_ip_add_bulk() (hammer_object.c:974-977) and hammer_ip_add_direntry() (:711-716) release a never-inserted memory record without HAMMER_RECF_DELETED_FE, and hammer_rel_mem_record() (:374-393) only destroys flagged records -- so any hammer_blockmap_reserve() failure at buffer-flush time (hammer_vnops.c:3251) permanently leaks one ~224B record (plus entry data in the direntry case) in the HAMMER-others zone; the author's own sibling path (hammer_io.c:1793-1795) sets the flag, proving the omission. Phase V could not organically produce a reservation failure on the lab guest in six experiment classes (plain fill, 40k tiny-file spray, mmap/msync -- which is gated too because vnode_pager_putpages calls VOP_WRITE, 6-writer unique-data races on fast and slow backing stores, and a run with the checkspace headroom removed via vfs.hammer.limit_dirtybufspace=2M): the checkspace gate plus the effectively synchronous strategy pipeline keeps the blockmap from ever running dry behind the gate on this hardware. Residual real triggers (freemap bread I/O errors, concurrent reblock/prune/mirror, drain-lag topologies where in-flight dirty exceeds the 49MB per-mount reserve which is half the ~103MB global dirty cap, reduced limit_dirtybufspace) keep the finding Medium/likely; guest stayed healthy, no panic, no leak observed, hence not_reproduced.", "exploit_chain": "", "evidence": [ "findings/poc/DF-3012/VERDICT.md (full narrative incl. per-experiment results)", "findings/poc/DF-3012/EXPERIMENTS.md (E1-E6 chronological log)", "findings/poc/DF-3012/run.log (decisive E6 run: sysctl headroom removed, 0 'reservation failed', zone 10->184 allocs churn only, persistence stage flat)", "findings/poc/DF-3012/env.txt (guest uname, INVARIANTS kernel, zone snapshot, sysctl state)", "sys/vfs/hammer/hammer_object.c:974-977 vs sys/vfs/hammer/hammer_io.c:1793-1795" ], "kernel_refs": [ "sys/vfs/hammer/hammer_object.c:974", "sys/vfs/hammer/hammer_object.c:711", "sys/vfs/hammer/hammer_object.c:363", "sys/vfs/hammer/hammer_vnops.c:3251", "sys/vfs/hammer/hammer_blockmap.c:419", "sys/vfs/hammer/hammer_blockmap.c:1267", "sys/vfs/hammer/hammer_io.c:1793" ], "poc_changes": "Four PoC generations: (1) write-fill+mmap/msync loops (mmap proved gated via VOP_WRITE), (2) tiny-file spray op3012.c 20k/40k files, (3) 6-parallel unique-data writers with prebuilt random source on fast/slow images (dedup defeated after discovering E1's low-entropy pages deduped), (4) deterministic attempt with vfs.hammer.limit_dirtybufspace=2M. writers.sh quoting for 'su -m nobody' fixed via executable script.", "attempts": 6, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 4200, "guest_dirty": 1, "build_cmd": "cc -O -o /tmp/op3012 /tmp/op3012.c -Wall", "run_cmd": "sh /tmp/run3012.sh (root harness; attacker processes as nobody)", "code_hash": "4292d0978cdce728764afa45da87f3be13c707d905b546eef725c66730ff2605", "notes": "Not a memory-corruption primitive: permanent kernel heap resource leak (availability) per failed direct-write reservation; no uid0 route. Side observation logged for triage (out of file scope): msync(2) returns success while vnode_pager_putpages fails the write with ENOSPC (dmesg 'vnode_pager_putpages: I/O error 28'), i.e. the pager error is not propagated to userspace.", "recommended_fix": "Set HAMMER_RECF_DELETED_FE on the record before hammer_rel_mem_record() in both error paths (hammer_object.c:711-716, :974-977), matching hammer_io.c:1793 -- see findings/poc/DF-3012/fix.diff (git-apply verified).", "fix_status": "not_testable", "fix_kernel_uname": "", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree and git-apply --check verified; kernel build validation skipped because the leak trigger (blockmap reservation failure) could not be reproduced on the baseline guest, so there is no observable to compare against.", "fix_evidence": "findings/poc/DF-3012/fix.diff" } |