DragonFlyBSD Kernel Audit
DF-2644 / verdict.json
← back to finding ↓ download raw
{
 "finding_id": "DF-2644",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "panic",
 "confidence": "certain",
 "verdict": "REPRODUCED on fault-injection kernel A (stock + sysctl-gated EIO injector with byte-exact real-media semantics, volume-gated to the 512MB test fs): sync on a PFS whose iroot chain cannot be re-read panics with Fatal trap 12, fault VA 0x200, 'Stopped at hammer2_xop_inode_flush+0x39c: repe movsq' - exactly the unguarded 'pmp->pfs_iroot_blocksets[clindex] = chain->data->ipdata.u.blockset' at hammer2_flush.c:1336-1337 with chain->data == NULL after hammer2_chain_load_data EIO (chain.c:1003-1008). The designed handlers one frame away ('hammer2: chain error during flush', 'PARENT ERROR DURING FLUSH LOCK') demonstrably work; this single deref ignores both chain->error and the discarded hammer2_flush() return. Fix validated on kernel B (only delta = fix.diff): identical workload+message sequence passes the site with no fault; residual later panic is the unrelated pre-existing chain.c:3112 KKASSERT(parent->error==0) via create/strategy retry paths (documented, belongs to chain.c audit).",
 "exploit_chain": "",
 "evidence": [
  "findings/poc/DF-2644/panic.txt (kernel A serial: chain-error handler messages then Fatal trap 12 VA 0x200 at hammer2_xop_inode_flush+0x39c)",
  "findings/poc/DF-2644/fix_run.log (kernel B: same sequence, NO xop_inode_flush fault, residual 3112 panic)",
  "findings/poc/DF-2644/fix_run_partial_3112.txt (kernel B arm=100000 variant, annotated contrast vs kernel A)",
  "findings/poc/DF-2644/inject.diff (environment simulator, never applied to the audited sys/ tree)",
  "findings/poc/DF-2644/fix.diff (the fix: guard + flush_error propagation)",
  "findings/poc/DF-2644/run_df2644_inj.sh, validate_fix_df2644.sh (triggers)",
  "findings/poc/DF-2644/build_kernelA2.sh / build_kernelB.sh (nativekernel build drivers)",
  "findings/poc/DF-2644/VERDICT.md (full narrative)"
 ],
 "kernel_refs": [
  "sys/vfs/hammer2/hammer2_flush.c:1334-1338",
  "sys/vfs/hammer2/hammer2_flush.c:1319-1322",
  "sys/vfs/hammer2/hammer2_flush.c:671-679",
  "sys/vfs/hammer2/hammer2_chain.c:998-1009",
  "sys/vfs/hammer2/hammer2_chain.c:147-166"
 ],
 "poc_changes": "Original sketch (vn detach / truncate backing file) was unrunnable: VNIOCDETACH refuses while the mount holds the device (vn.c:464), truncation yields short reads without B_ERROR (vn.c:342-371). Replaced with a sysctl-gated EIO injector inside _hammer2_io_getblk (after DIO setup, exactly where breadnx reports errors); first injector revision returning *diop=NULL was itself an artifact (violated the always-valid-dio contract, crashed in _hammer2_io_putblk) and was corrected to error-injection; volume-gated by volu_size after the guest ROOT hammer2 was also being failed (its boot-time writes panicked via chain.c:3112). Trigger v2 uses metadata-only dirt + bounded arm count.",
 "attempts": 6,
 "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Sat Aug 29 19:59:33 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (kernel A, panic run)",
 "runtime_sec": 6900,
 "guest_dirty": 0,
 "build_cmd": "cd /usr/src && make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC",
 "run_cmd": "sh /root/df2644/run_df2644_inj.sh",
 "code_hash": "see manifest.json artifacts_sha256",
 "notes": "Residual panic chain.c:3112 (KKASSERT parent->error==0 via xop_inode_create_ins / assign_physical) is a separate defect surfaced by the same scenario - recommend filing under hammer2_chain.c. Injector never touches the audited sys/ tree; guest reset with-src after runs.",
 "recommended_fix": "Guard the blockset copy with 'chain->error == 0 && chain->data != NULL' and propagate hammer2_flush()'s return into flush_error so a failed iroot flush also skips volume-header sync (fix.diff)",
 "fix_status": "fixed",
 "fix_kernel_uname": "DragonFly 6.5-DEVELOPMENT kernel B (only delta = fix.diff; in-guest nativekernel)",
 "fix_baseline_reproduced": 1,
 "fix_patched_reproduced": 0,
 "fix_verdict": "kernel B (stock + DF-2644 fix.diff only) passes the identical EIO-injected sequence with no fault at the site; the designed error handlers operate.",
 "fix_evidence": "fix_build.log / fix_run.log / VERDICT.md"
}