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)
PoC verification
Evidence pack
findings/poc/DF-4242 Β· 14 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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_intrfrom 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
fixedValidated 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
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.
No comments yet.