⬢ DragonFlyBSD Kernel Audit
DF-5843 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5843",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "Reproduced on the audit guest (DragonFly 6.5-DEVELOPMENT, stock kernel). A crafted hammer2 image whose regular file carries an INODE-typed direct blockref (check tree repaired so the media passes every kernel validation) panics the kernel at hammer2_xops.c:1582 (KKASSERT(0) in the truncation delete loop of hammer2_xop_inode_chain_sync) when any user runs open(O_RDWR)+ftruncate()+close() on the file. chain_lookup returns children of any bref type (hammer2_chain.c:2482-2511) and the loop switches on bref.type without checking chain->error, so the assert is unconditional. Impact is a reliable local kernel panic (DoS), not memory corruption; no escalation path exists from this site because the assert stops execution before any further use of the planted chain. fix.diff (KKASSERT(0) -> error = HAMMER2_ERROR_CHECK) was built as a single-fix kernel and validated: baseline panics, patched kernel survives the identical trigger.",
  "exploit_chain": "crafted image (mkbadimg: DATA bref -> INODE bref + xxhash64/icrc check-tree fixpoint) -> mount (privileged mount or usermount policy) -> unprivileged open(O_RDWR)/ftruncate/close -> hammer2_xop_inode_chain_sync truncate scan (:1570) returns planted chain -> switch on bref.type -> KKASSERT(0) at :1582 -> kernel panic, all CPUs stopped. No memory-corruption primitive; ceiling is DoS.",
  "evidence": "panic.txt (panic + backtrace at hammer2_xops.c:1582), run.log (full pipeline incl. mkbadimg fixpoint output and trigger), fix_run.log (patched kernel: SURVIVED, exit 0), fix_build.log (nativekernel BUILD_RC=0), VERDICT.md (narrative)",
  "kernel_refs": [
    "sys/vfs/hammer2/hammer2_xops.c:1575-1594",
    "sys/vfs/hammer2/hammer2_xops.c:1582",
    "sys/vfs/hammer2/hammer2_chain.c:2482-2511",
    "sys/vfs/hammer2/hammer2_vnops.c:1252-1271",
    "sys/vfs/hammer2/hammer2_inode.c:1695-1735"
  ],
  "poc_changes": "no seed (pass-3 fresh finding); authored from scratch. Iterations: (1) inode-discovery signature fixed after learning detached inodes store the 0x%016jx inum string in filename[]; (2) single-level check repair broke mount -> replaced with fixpoint propagation of xxhash64 checks + volume-header icrc_sects[6]/[7] + icrc_volheader; (3) 8-byte write clobbering u32 icrc_sects fixed; (4) planted bref data_off radix retargeted 16->10 so the chain instantiates at HAMMER2_INODE_BYTES.",
  "attempts": 4,
  "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": 3240,
  "guest_dirty": 0,
  "build_cmd": "cc -O -o /root/mkbadimg /root/mkbadimg.c /usr/src/sys/vfs/hammer2/xxhash/xxhash.c /usr/src/sys/libkern/icrc32.c && cc -O -o /root/trig /root/trig.c",
  "run_cmd": "sh run.sh   (pristine image -> mkbadimg -> mount /dev/vn0@BAD /mnt -> /root/trig /mnt/BIGTGTNAME 65536)",
  "code_hash": "sha256 mkbadimg.c=2cd4955069ebb29bafca59dd9fd61aeb12551a282672c440ac2b9675a4bba536 trig.c=4417901a6301b23af531116dbbd7dea8c61b13efee281a5ee1e1221560c06823",
  "notes": "Trigger (ftruncate) is unprivileged once the image is mounted; mounting requires root or usermount policy (vfs.usermount=0 on guest). Same code path is reachable on legitimately corrupted media. Guest reset clean (vm.sh reset with-src) after fix validation. Pass-3 sibling note for other files audits: hammer2_inode.c:453 chain_and_parent derefs chain after a NULL acquisition from the cluster array (reachable via hammer2_chain_inode_find callers) - left to hammer2_inode.cs own audit.",
  "recommended_fix": "Replace KKASSERT(0) at hammer2_xops.c:1582 with error = HAMMER2_ERROR_CHECK (fail the truncation gracefully on inconsistent media); see fix.diff.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Single-fix kernel built from fix.diff (make nativekernel KERNCONF=X86_64_GENERIC, BUILD_RC=0), installed and booted (#1 Wed Oct 14 00:21:07 UTC 2026). Identical PoC pipeline re-run: no panic, trig exits 0, guest stays up (SURVIVED: no panic). Baseline stock kernel panicked at the same site. fix_patched_reproduced=false means the BUG did not reproduce on the patched kernel (expected direction).",
  "fix_evidence": "fix_run.log (patched-kernel run), fix_build.log (kernel build), run.log+panic.txt (baseline panic)"
}