⬢ DragonFlyBSD Kernel Audit
DF-3962 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3962",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Certain source-level race: hptiop_post_req_mvfrey arms a 20s per-CCB callout (hptiop.c:2647-2650) whose handler hptiop_reset_adapter (2244-2250) polls iop_intr via hptiop_send_sync_msg (899-906) WITHOUT hba->lock, while hptiop_pci_intr (2163-2169) runs the same iop_intr WITH the lock; the mvfrey outlist drain (782-795) uses the shared non-atomic outlist_rptr, so concurrent execution completes the same tag twice -> hptiop_free_srb twice (freelist aliasing, two CCBs share one srb) and xpt_done(ccb) twice (CAM UAF). Also: the timed-out CCB is never completed (callout arg is hba), and the reset busy-waits up to 60s in softclock. Siblings hptmv/hpt27xx lock in their timeout handlers. Not reproduced: no mvfrey HBA on the audit guest (env.txt).",
  "exploit_chain": "mvfrey command stalls >20s while later completions arrive -> callout fires hptiop_reset_adapter on CPU0 (unlocked) as a completion IRQ arrives on CPU1 (locked) -> both drain the same outlist entry -> double srb completion -> srb appears twice on the free list -> next two posts alias one request buffer (16-byte-stride descriptor corruption between commands) and double xpt_done panics or corrupts CAM state; independently the 60s DELAY loop in softclock stalls the CPU (DoS).",
  "evidence": "VERDICT.md (path:line race chain + sibling comparison), trigger.c (source excerpt + hardware recipe), env.txt, fix.diff (lock acquisition, git apply --check clean)",
  "kernel_refs": [
    "sys/dev/raid/hptiop/hptiop.c:2647",
    "sys/dev/raid/hptiop/hptiop.c:2244",
    "sys/dev/raid/hptiop/hptiop.c:891",
    "sys/dev/raid/hptiop/hptiop.c:899",
    "sys/dev/raid/hptiop/hptiop.c:2163",
    "sys/dev/raid/hptiop/hptiop.c:782",
    "sys/dev/raid/hptiop/hptiop.c:634",
    "sys/dev/raid/hptiop/hptiop.c:639",
    "sys/dev/raid/hptmv/entry.c:2626",
    "sys/dev/raid/hpt27xx/hpt27xx_osm_bsd.c:530"
  ],
  "poc_changes": "No runnable PoC: needs an mvfrey-family HBA (RR43xx/45xx) with a stalled command and concurrent completion; trigger.c carries the annotated source chain and hardware recipe.",
  "attempts": 1,
  "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": 8,
  "guest_dirty": 0,
  "build_cmd": "guest: cd /usr/src/sys/dev/raid/hptiop && patch -p1 < fix.diff && make   # after make obj",
  "run_cmd": "dfbsd-qemu/vm.sh run_root pciconf -lv | grep -i 1103; ls -la /boot/kernel/hptiop.ko",
  "code_hash": "3910c9facb7bf99b56840392e91f2fdc095d9676c5d278579182ccab67ffc8d3",
  "notes": "Pass-2 finding (deeper than DF-1311..1313: multi-path lifetime/race analysis). Lock is LK_CANRECURSE (hptiop.c:1899) so the fix works for both the callout and XPT_RESET_BUS paths.",
  "recommended_fix": "Take hptiop_lock_adapter in hptiop_reset_adapter before send_sync_msg (fix.diff); upstream should additionally complete/abort the timed-out CCB and drop the 60s callout-context busy-wait.",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff serializes the callout-driven iop_intr with the hard-IRQ path by acquiring the recursive adapter lock in hptiop_reset_adapter; git apply --check passes against pristine sys/. Runtime validation impossible without the HBA fix.diff applied to the guest /usr/src copy and the hptiop.ko module rebuilt clean with -Werror (build.log; combined with the other four hptiop fix.diffs of this batch); runtime validation still impossible without the HBA.",
  "fix_evidence": "fix.diff (git apply --check clean); fix.diff applied to the guest /usr/src copy and the hptiop.ko module rebuilt clean with -Werror (build.log; combined with the other four hptiop fix.diffs of this batch); runtime validation still impossible without the HBA."
}