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

panic("DPT Rebooted") on device-fed register signature β€” a rebooting or hostile HBA takes down the kernel (DF-4042/4098 hostile-input family)

Summary

When a completion carries HA_SERROR, dpt_intr reads four HBA registers and if offsets 2..5 spell 'DPTH' it executes panic('DPT Rebooted'). All inputs are device-fed: a controller that merely reboots mid-I/O (firmware crash, power glitch, PCI reset) panics the whole machine; the adjacent comment even says 'This is incomplete, fix me'. Drain-and-continue fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4242 Β· 14 files
FileTypeDescriptionSize
dfdpt_rig.c β€” 37.5 KB view raw
dfdpt_ctl.c β€” 7.5 KB view raw
Makefile β€” 108 B ↓ download
dpt.h β€” 38.3 KB view raw
build.sh β€” 92 B view raw
run.sh β€” 197 B view raw
build.log β€” 1.6 KB view raw
run.log β€” 3.4 KB view raw
panic.txt β€” 566 B view raw
fix_validation.log β€” 3.7 KB view raw
fix.diff β€” 697 B view raw
verdict.json β€” 3.5 KB view raw
VERDICT.md β€” 2.8 KB ↓ raw
env.txt β€” 532 B view raw
VERDICT.md
↓ download raw

DF-4242 β€” VERDICT

REPRODUCED (deterministic kernel panic from device-fed registers; fix validated on a rebuilt kernel β€” no panic, drain-and-continue).

What was proven

The trigger is entirely device-fed and needs nothing else: a status packet with an in-range ccb_busaddr and EOC=1, plus register values HA_RSTATUS & HA_SERROR and 'DPTH' at offsets 2..5. Dispatching the production dpt_intr (0xffffffff80439670 in the shipped X86_64_GENERIC image) over the rig's virtual register file produced, on the serial console:

dpt9: HBA rebooted.
      All transactions should be resubmitted
dpt9: >>---->>  This is incomplete, fix me....  <<----<<panic: DPT Rebooted
cpuid = 2
dpt_intr() at dpt_intr+0x2c2 0xffffffff80439932

The backtrace shows the panic executing inside the production handler itself. The panic fires at dpt_scsi.c:1566, before ccb = dccb->ccb (line 1571) β€” no in-flight I/O is required, the CCB is never dereferenced: the register signature alone is lethal.

A controller that merely reboots mid-I/O (firmware crash, power glitch, PCI reset) presents exactly this signature; a hostile device trivially does. The kernel β€” the whole machine β€” goes down: availability impact with zero privileges beyond being the HBA on the bus (or its virtualization/passthrough equivalent).

Fix validation (fix.diff applied, kernel rebuilt + rebooted)

The rig re-ran the identical trigger against an ACTIVE in-flight CCB (queued through production dpt_action), so the packet passes the DF-4241 DCCB_ACTIVE guard and reaches the reboot branch itself (fix_validation.log):

dpt9: HBA rebooted.
      All transactions should be resubmitted
dpt9: >>---->>  This is incomplete, fix me....  <<----<<Encountered bogus status packet
[dptrig] PANIC: dpt_intr RETURNED (unexpected!)
  • no panic: the fixed branch drains the interrupt (status read) and continues the completion loop; the loop then exits cleanly on the bogus next packet;
  • the ioctl returned to userland (PANIC_RC=0), guest stayed up (uptime verified);
  • in-flight commands are recoverable through the existing dpttimeout/CAM timeout path, which is the fix's intended recovery mechanism.

Caveats

  • The ctl prints "dpt_intr RETURNED (unexpected!)" β€” that message text predates the fix; on the patched kernel the return is the EXPECTED outcome (no panic).
  • The rig invoked dpt_intr from an ioctl thread; the panic path is register- and softc-driven only, so hardirq context is immaterial here.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Validated on the rebuilt kernel: identical trigger on an ACTIVE ccb prints the reboot banner but drains and continues -- no panic, ioctl returns, guest stays up.

fix_validation.log
↓ fix.diffper-fix-DF-4242

Confirmed kernel references

Detail

Exploit chain

device (rebooting or hostile) presents HA_SERROR + 'DPTH' signature on a completion -> production dpt_intr panic("DPT Rebooted") -> kernel down. Single-shot, zero-privilege-from-the-OS-side, purely device-fed DoS.

Evidence (decisive lines)

run.log (serial console: 'dpt9: HBA rebooted.' + 'This is incomplete, fix me' + 'panic: DPT Rebooted', backtrace dpt_intr+0x2c2 <- rig_ioctl <- dev_dioctl); panic.txt (panic block); fix_validation.log (same trigger on patched kernel: banner + 'Encountered bogus status packet' drain, '[dptrig] PANIC: dpt_intr RETURNED', guest up)

PoC changes

No seed PoC existed. Added the 'panic' ioctl to the production-handler dispatch rig: writes the device-fed status packet + poisons the virtual register file (DPTH / HA_SERROR), then calls production dpt_intr. On the fix-validation run the trigger was aimed at an ACTIVE ccb (queued through production dpt_action) so the fixed reboot branch itself is exercised rather than being pre-empted by the DF-4241 inactive-CCB guard.

Verified recommended fix

Replace panic() with interrupt drain + continue; let CAM timeouts recover in-flight commands (fix.diff).

Verdict

REPRODUCED: with an in-range, EOC-set status packet and five device-fed register bytes (offsets 2..5 spelling 'DPTH' plus HA_SERROR in HA_RSTATUS), the production dpt_intr (0xffffffff80439670 in the shipped kernel, panic site dpt_intr+0x2c2) executes panic("DPT Rebooted") -- serial console shows the production 'dpt9: HBA rebooted ... This is incomplete, fix me' banner immediately followed by 'panic: DPT Rebooted' with the backtrace through rig_ioctl. The panic fires at dpt_scsi.c:1566 BEFORE ccb is dereferenced (line 1571), so no in-flight I/O is needed: a rebooting (or hostile) HBA alone takes the whole kernel down. FIX VALIDATED on a rebuilt kernel with the identical trigger aimed at an ACTIVE in-flight CCB (so it passes the DF-4241 guard and reaches the reboot branch): production dpt_intr prints the same banner, drains the interrupt, continues -- NO panic; the ioctl returned to userland (RC=0) and the guest stayed up, with in-flight commands left to dpttimeout/CAM recovery.