⬢ 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"
}