DF-3982 / verdict.json
{ "finding_id": "DF-3982", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "sbp_recv1() executes in the fwohci hard-interrupt path under crit_enter() (fwohcivar.h:37 FWOHCI_TASKQUEUE=0; fwohci.c:2688 crit; firewire.c:991 act.hand; sbp.c:1823) yet calls DragonFlys now-synchronous callout_stop() at sbp.c:1600 (mgm_ocb_timeout), sbp.c:2590 and sbp.c:2705 (CCB timeouts). kern_timeout.c:1091/_callout_cancel_or_stop(sync=1) ssleeps on costp (kern_timeout.c:923) whenever the callback is queued or INPROG on any CPU, so the fwohci IRQ thread is put to sleep - inside a critical section - for the full duration of sbp_mgm_timeouts unbounded body (sbp.c:2126-2146 -> sbp_reset_start -> fw_asyreq allocation path), and the INPROG-blocked softclock thread starves every tsleep-timeout sharing its CPU. Mechanism PROVEN live on the shipped guest kernel via replica B: caller captured in D5 costp with crit held, callback thread B2 bcb INPROG, and a third thread D2 wkdelay starved by the wedged wheel (run.log); negative control: stop of a non-INPROG callout returns in 9 ms. End-to-end sbp trigger is hardware-gated (no OHCI-1394 on guest) hence inconclusive rather than reproduced.", "exploit_chain": "hostile FireWire device times (or sprays) a status write matching the pending mgm ORB address while the 5 s mgm_ocb_timeout callback (or a CCB timeout callback) is executing on a softclock thread -> fwohci interrupt thread enters callout_stop at sbp.c:1600/2590/2705 -> sleeps in costp holding crit until the callback body finishes (its own duration is attacker-inflatable via bus congestion/tlabel pressure) -> FireWire IRQ stalls; wedged softclock wheel starves unrelated kernel tsleep timeouts on that CPU -> local/remote DoS.", "evidence": "run.log (live ps captures: 1237 D5 costp sysctl, -1 12 B2 bcb softclock 2, cascade 1256 D2 wkdelay sysctl); VERDICT.md (full chain path:line); console_tail.txt (serial log); build.log; env.txt (no FireWire hw); fix.diff (callout_stop_async at the 3 sites + mgm_ocb_cur recheck, patch --dry-run clean)", "kernel_refs": [ "sys/dev/disk/sbp/sbp.c:1600", "sys/dev/disk/sbp/sbp.c:2590", "sys/dev/disk/sbp/sbp.c:2705", "sys/dev/disk/sbp/sbp.c:1823", "sys/kern/kern_timeout.c:1091", "sys/kern/kern_timeout.c:923", "sys/bus/firewire/fwohci.c:2688", "sys/bus/firewire/fwohci.c:2833", "sys/bus/firewire/fwohcivar.h:37", "sys/bus/firewire/firewire.c:991" ], "poc_changes": "Replica iterations: (1) tsleep-with-timeout inside the callback self-deadlocked the softclock thread (tsleep timeouts are callout-based on the same wheel) - replaced with a no-timeout body released by a controller sysctl; (2) DELAY busy-wait body froze userland scheduling on the callback CPU so the stopper never landed INPROG - replaced with the blocking-sleep body; final design reproduces the sbp state exactly and cleanly unwinds via the wake sysctl.", "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": 480, "guest_dirty": 0, "build_cmd": "cd /root/kmod && make", "run_cmd": "kldload ./sbpprep.ko && sysctl kern.sbpprep_armb=1 && (sysctl -n kern.sbpprep_stopb=1 >/dev/null 2>&1 </dev/null &) && sleep 3 && ps -o pid,stat,wchan,comm -ax | grep sysctl", "code_hash": "c4245b4d7304e28974191235a02ccdcf60287b38fd2b76e8e7b2974689a8bda5", "notes": "Guest intentionally wedged during RUN 2 capture; reset with-src performed before hand-off (dmesg grep sbpprep == 0 on the fresh boot). DF-3715/DF-3738/DF-3760 are the same kernel semantics in net drivers; this is the sbp.c hard-IRQ instance.", "recommended_fix": "Use callout_stop_async() on the three interrupt-path sites and re-validate target->mgm_ocb_cur == ocb in sbp_mgm_timeout before acting (fix.diff); longer term, redesign the mgm queue locking.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applies cleanly; behavior delta cannot be exercised on this guest (sbp path needs FireWire hardware). The mechanism fix at the kern_timeout level is already proven correct in the negative control (non-INPROG stops never block).", "fix_evidence": "fix.diff (3x callout_stop_async + mgm_ocb_cur recheck); run.log RUN 1 negative control" } |