β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4350

adv_run_doneq walks the device-fed done-queue FWD chain with no iteration bound β€” cyclic chain = interrupt-context livelock / hard system hang (DF-4307 livelock facet, narrow twin)

Summary

The done-queue walk terminates solely on the LRAM FWD byte; the only corruption guards are #ifdef DIAGNOSTIC panics compiled out of release kernels. A corrupt/hostile cyclic chain spins the interrupt forever (crit section held, ~10 LRAM port I/O ops per iteration). Guest model over a 3-entry circular chain never terminates within a 1e6 cap. Budget-the-walk fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4350 Β· 16 files
FileTypeDescriptionSize
df43xx_rig.c β€” 41.5 KB view raw
advlib.h β€” 25.4 KB view raw
Makefile β€” 117 B ↓ download
build.sh β€” 152 B view raw
prime.sh β€” 1.1 KB view raw
build_fixed.sh β€” 1.1 KB view raw
panic.baseline.txt β€” 814 B view raw
run.4349only-livelock.log β€” 1.7 MB ↓ download
run.bothfixed.log β€” 34.3 KB view raw
run.log β€” 986 B view raw
fix_run.log β€” 819 B view raw
fix_build.log β€” 599 B view raw
build.log β€” 929 B view raw
fix.diff β€” 1.1 KB view raw
env.txt β€” 1.1 KB view raw
verdict.json β€” 5.6 KB view raw

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

On the shipped kernel the cyclic chain panics (DF-4349 sink); on the both-fixed kernel the identical dispatch logs 'adv9: done queue walk exceeded 276 entries, stopping (corrupt LRAM?)' and adv_intr returns after 4273 LRAM data-port services, guest alive, control completions unaffected. baseline_reproduced=1 (system-halting), patched_reproduced=0.

fix_run.log / run.bothfixed.log: 'done queue walk exceeded 276 entries' + 'df43xx[4]: adv_intr RETURNED after 4273 data-port services'; panic.baseline.txt for the baseline halt
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #2: Thu Oct 15 14:56:52 UTC 2026 (both fixes; budget present)

Confirmed kernel references

Detail

Exploit chain

Corrupt/hostile AdvanSys LRAM done-queue FWD bytes forming a cycle -> production adv_run_doneq loop (crit section held in the real ISR) never sees ADV_QLINK_END -> shipped kernel: revisit panic via DF-4349 sink (hard crash); DF-4349-fixed kernel: infinite drop-loop = interrupt livelock / permanent kernel-thread wedge, watchdog-class DoS. Requires physical AdvanSys HBA with buggy/hostile firmware or a hostile SCSI peripheral; no unprivileged-user or remote path.

Evidence (decisive lines)

panic.baseline.txt (cyclic chain -> panic on shipped kernel), run.4349only-livelock.log (full serial: 'entering production adv_intr with cyclic FWD chain', 28883 drop lines, no RETURNED, dbg_hits climb, kldunload EBUSY), run.bothfixed.log + fix_run.log (budget break at ADV_MAX_TOTAL_QNG+ADV_MAX_SG_LIST=276, adv_intr RETURNED after 4273 services), run.log (condensed livelock capture)

PoC changes

Replaced the seed userspace model with the production-handler KLD dispatch rig shared with DF-4349 (fabricated softc + watchpoint-emulated ASC LRAM + nm-resolved kernel adv_intr). Added scenario 4 (synchronous cyclic-chain dispatch) and scenario 6 (dedicated-kthread dispatch with heartbeat callouts and a kern.df43xx.dbg_hits counter that counts every emulated LRAM data-port access made by the spinning production walk) plus the two rebuilt-kernel variants that isolate the livelock (DF-4349 fix only) and validate the budget fix (both fixes).

Verified recommended fix

Budget the done-queue walk at ADV_MAX_TOTAL_QNG + ADV_MAX_SG_LIST iterations and break with a diagnostic when exceeded (a legitimate done queue can never be longer).

Verdict

REPRODUCED as a system-halting DoS through the production adv_intr of the shipped kernel binary, with the pure livelock isolated on a purpose-built kernel. Cyclic device-fed FWD chain (6->7->6): on the SHIPPED kernel the unbounded walk revisits completed slots and panics via the DF-4349 double-completion sink (panic.baseline.txt) - a hard device-fed crash. On a kernel rebuilt with ONLY the DF-4349 validation fix (kernel #3), the walk drops the revisited entries and NEVER TERMINATES: the dispatch kthread wedges inside production adv_run_doneq (no RETURNED marker), the console floods with 28,883 'dropping completion' lines, and the LRAM data-port service counter (kern.df43xx.dbg_hits, incremented by the #DB chip emulator on every production port access) climbs monotonically across six samples (9985 -> 24895 -> 360550 -> 365530 -> 425830 -> 433270, ~2500 port ops/s); kldunload is refused EBUSY because the thread is still spinning - exactly the filed interrupt-context livelock. On the kernel with BOTH fixes (kernel #2) the walk is budget-bounded: 'done queue walk exceeded 276 entries, stopping' and adv_intr RETURNS after 4273 port services, guest alive. Termination of the walk is controlled solely by the device-written FWD byte (advansys.c:1043/:1068/:1114); no iteration bound exists in the unpatched driver - confirmed structurally and behaviorally.