dpt_pci_attach() bus_setup_intr failure leaves XPT-registered SIMs, CAM wildcard paths, shutdown_post_sync handler and softc (on global dpt_softcs) live against released io/irq β phantom CAM bus issues bus_space I/O through a released rman record and never completes a command
Summary
The setup_intr-failure goto bad: undoes nothing dpt_attach registered - the phantom SIM stays XPT-resolvable forever, dpt_action pokes registers through the released window, no completion is ever reaped (boot scan hangs), and dptshutdown keeps firing each reboot. Hardware-gated boot-time wedge; full reverse-order teardown fix (3-file, apply-clean).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5153 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 4.8 KB | β raw | |
| VERDICT.md | β | 4.7 KB | β raw | |
| fix.diff | β | 3.1 KB | view raw | |
| verdict.json | β | 3.6 KB | view raw | |
| env.txt | β | 992 B | view raw |
DF-5153 β dpt_pci_attach() bus_setup_intr failure leaves XPT-registered SIMs, CAM paths, shutdown handler and softc live against released io/irq
File: sys/dev/raid/dpt/dpt_pci.c:163-179 (trigger), :159 (setup)
Class: incomplete error-path unwind β logical UAF of bus resources +
permanent leak + unkillable CAM I/O (CWE-459 Incomplete Cleanup)
Severity: Low (hardware-gated: needs a DPT 0x1044:0xa400 HBA and an
interrupt-registration failure at attach)
Distinct from DF-2151 (known, not re-reported): DF-2151 is the wrong-rid
bus_release_resource on the bad: path. This finding is everything else
that path fails to unwind β the CAM/XPT lifetime, the shutdown handler, the
DMA machinery and the softc. (Note the IRQ release at dpt_pci.c:176-177 uses
rid 0, which is the rid the IRQ was allocated with at :103-105 β correct;
only the io rid is wrong, and that half is DF-2151.)
The bug
dpt_pci_attach reaches bus_setup_intr only after the controller is fully
brought online:
crit_enter();
if (dpt_init(dpt) != 0) { ... } /* DMA tags, CCB array, sg maps */
/* Register with the XPT */
dpt_attach(dpt); /* dpt_pci.c:159 */
crit_exit();
error = bus_setup_intr(dev, irq, 0, dpt_intr, dpt, &ih, NULL);
if (error) {
device_printf(dev, "Unable to register interrupt handler\n");
error = ENXIO;
goto bad; /* dpt_pci.c:168 */
}
...
bad:
if (io)
bus_release_resource(dev, iotype, 0, io); /* wrong rid = DF-2151 */
if (irq)
bus_release_resource(dev, SYS_RES_IRQ, 0, irq); /* correct rid */
return (error);
By the time bus_setup_intr runs, dpt_attach (dpt_scsi.c:1450-1490) has:
cam_sim_alloc'd up toMAX_CHANNELSSIMs sharing one devq andxpt_bus_register'd each (dpt_scsi.c:1466-1473),xpt_create_path'd wildcard paths for each (dpt_scsi.c:1475-1482),- released the shared devq (dpt_scsi.c:1485),
EVENTHANDLER_REGISTER'dshutdown_post_sync β dptshutdown, discarding the tag (dpt_scsi.c:1487-1488),
and dpt_alloc (dpt_scsi.c:1153-1169) has TAILQ-link'd the softc onto the
global dpt_softcs list (:1165). None of this is undone on the failure
path: bad: touches only io/irq; dpt_free is never called; no bus is
deregistered; no sim/path freed; the shutdown handler stays registered; the
softc stays on dpt_softcs; the DMA'able CCB array, sg maps and three DMA
tags stay allocated forever.
Consequences (why it is not merely cosmetic)
- Phantom SIM in CAM.
xpt_bus_registeris global state independent of newbus attach status. After the failed attach the bus/sim/paths remain fully resolvable; CAM's own boot-time scan (and anything else that compiles a path to that bus) reachesdpt_actionβdptexecuteccb, which pokesdpt_outb()throughdpt->tag/bshβ a bus_space handle to an rman record that was just released (or, with DF-2151's wrong-rid no-op, leaked). Cross-device register corruption on x86 PIO; MMIO variant touches the re-mapped page owner. - Unkillable I/O. No interrupt handler was installed, so nothing the HBA completes is ever reaped β every command routed to the phantom bus hangs in CAM forever (boot-time wedging of the SCSI scan path).
- Shutdown-time use of released state.
dptshutdown(dpt_scsi.c:1717-1733) still fires on every reboot and issuesdpt_send_immediatethrough the released/leaked register window. - Permanent leak of the CCB DMA memory, sg maps, three child DMA tags,
io (via the DF-2151 no-op) β and see DF-5154 for
parent_dmat, which is additionally never destroyed even wheredpt_freeis called.
No kernel-heap corruption primitive is in scope here (bus-space logical UAF plus leak), and the trigger is hardware/boot-time β there is no unprivileged trigger and no uid=0 route; the class does not permit one.
Reproduction status
untested β hardware-gated. Verified on the audit guest
(pciconf -l β no vendor 0x1044 device; see env.txt): the entry path
cannot fire there, and the defect is not driveable by any userland program
(absent the card). Line-level proof of the unwind gap is in VERDICT.md.
Family precedent: DF-5115 (ips, same shape) was filed untested for the
same reason; DF-5141 (mlx) was reproduced only because its primitive was a
genuine double-kfree driveable by a KLD harness β this one has no such
primitive to harness.
Fix
See fix.diff: full reverse-order teardown on the bus_setup_intr failure
path (free paths β deregister buses β free sims β deregister the shutdown
handler (tag now stored in the softc) β dpt_free β destroy parent_dmat),
plus the correct io rid in bad: (that hunk overlaps DF-2151's fix and is
included only because the unwind is meaningless while the release is a
no-op).
DF-5153 VERDICT β dpt_pci.c setup_intr-failure incomplete unwind
Status: untested (hardware-gated). Impact: none demonstrable on the
audit guest (no DPT controller present β verified, env.txt).
Confidence: certain that the defect exists as described (line-proven).
Fix: authored, not kernel-validated (fix.diff; baseline behavior
cannot be reproduced without the HBA, so fix validation is not_testable).
1. Root cause (line-certain)
sys/dev/raid/dpt/dpt_pci.c:151βdpt_init(dpt)succeeds (DMA tags at dpt_scsi.c:1235/1356/1370, CCB array at :1385, sg maps at :1254).sys/dev/raid/dpt/dpt_pci.c:159βdpt_attach(dpt)registers up to 3 SIMs + wildcard paths with XPT and theshutdown_post_synchandler (dpt_scsi.c:1466-1488); return value (channel count) is ignored by the glue β harmless here since >0 channels means live registrations either way.sys/dev/raid/dpt/dpt_pci.c:163-169βbus_setup_intrfailure jumps tobad:having undone nothing of the above.sys/dev/raid/dpt/dpt_pci.c:173-179βbad:releases only io/irq. The io release passes rid 0 for a resource allocated at ridPCIR_MAPS(=0x10)/PCIR_MAPS+4βpci_release_resource'resource_list_delete(rl, type, rid)lookup misses β EINVAL no-op β the io leaks (this half is DF-2151, known). The irq release at :176-177 uses rid 0, which matches the allocation rid at :103-105 β genuinely released while the device keeps its registers programmed (busmaster was forced on at :113-114).sys/kern/subr_bus.c:3328-3333βbus_release_resourceis a pure rid-keyed dispatch, confirming the asymmetry.
2. What stays alive (the defect)
| Object | Created at | Released on failure? |
|---|---|---|
| XPT buses/sims | dpt_scsi.c:1466-1473 | never (phantom SIM) |
| CAM wildcard paths | dpt_scsi.c:1475-1482 | never |
shutdown_post_sync handler (tag discarded) |
dpt_scsi.c:1487-1488 | never |
softc on global dpt_softcs |
dpt_scsi.c:1165 | never |
| CCB DMA memory + 3 DMA tags | dpt_init | never (dpt_free not called) |
| io resource | dpt_pci.c:88/94 | no-op leak (DF-2151) |
| irq resource | dpt_pci.c:104 | released (correct rid) β while the card can still assert it |
3. Reachability / threat model
Entry requires dpt_pci_probe to match PCI 0x1044:0xa400 (dpt_pci.c:61-66)
β real DPT SmartRAID hardware β and bus_setup_intr to fail (interrupt
vector exhaustion, MSI/MSI-X setup failure on the platform). Both are
boot/kldload-time conditions. No unprivileged local user trigger exists;
on hardware without the card the driver never attaches (verified on the
guest: pciconf -l shows no 0x1044 device). uid=0 escalation is not
applicable: no user-controlled grooming window, no kernel-heap primitive β
the residual primitives are (a) a CAM-reachable bus_space handle whose rman
record was released/re-allocatable, (b) an irq released under a
busmaster-enabled device, (c) permanent leaks, (d) never-completing CAM
commands (boot hang). Ceiling on real hardware: cross-device PIO/MMIO
corruption and boot-time DoS.
4. Why untested (honest classification)
- Guest has no DPT HBA (
env.txt) βdpt_pci_attachunreachable, and no userland program can reach any part of this path even with one present. - Unlike DF-5141 (mlx double-free β reproduced via KLD harness driving the
real
mlx_free()twice), the consequence here is logical (CAM/rman lifetime), not allocator-detectable: a harness that fabricates a softc and callsxpt_bus_register+bus_release_resourcewould only demonstrate that CAM keeps a sim whose resource was released β the code's own text β without adding evidentiary weight. Recorded as analysis-verified instead.
5. Fix
fix.diff (dpt_pci.c + dpt.h + dpt_scsi.c): reverse-order teardown on the
failure branch β free paths, deregister buses, free sims, deregister the
shutdown handler via a tag now stored in the softc, crit_enter;
dpt_free(dpt); crit_exit(); bus_dma_tag_destroy(dpt->parent_dmat)
(covers DF-5154 on this path); and the io rid correction in bad: (hunk
shared with DF-2151's fix). Not kernel-build-validated (no target hardware;
fix validation not_testable).
6. Kernel references
sys/dev/raid/dpt/dpt_pci.c:159, :163-169, :173-179, :88-94, :103-105, :113-114; sys/dev/raid/dpt/dpt_scsi.c:1165, :1235, :1356, :1370, :1385, :1466-1488, :1717-1733; sys/kern/subr_bus.c:3328-3333.
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
not_testablefix.diff authored post-verification against the read-only sys/ tree; git apply --check clean (dpt.h + dpt_scsi.c tag plumbing + dpt_pci.c teardown). Baseline cannot be reproduced on the guest (no DPT HBA), so patched-kernel validation is not_testable.
findings/poc/DF-5153/fix.diff (3-file unified diff, apply-checked); VERDICT.md section 5.
Confirmed kernel references
Detail
Evidence (decisive lines)
README.md (bug + consequence table), VERDICT.md sections 1-2 with the stays-alive table, fix.diff (git-apply-clean reverse-order teardown), env.txt (guest has no DPT PCI device). Decisive lines: sys/dev/raid/dpt/dpt_pci.c:163-169 vs :159 and bad: at :173-179; dpt_scsi.c:1466-1488.
PoC changes
no seed PoC existed; none authored - path is unreachable without DPT hardware (KLD harness would only restate the code text; no allocator-detectable primitive unlike DF-5141)
Verified recommended fix
On bus_setup_intr failure, tear down in reverse order before bad: xpt_free_path each paths[ch], xpt_bus_deregister+cam_sim_free each sims[ch], EVENTHANDLER_DEREGISTER(shutdown_post_sync, tag stored in softc), crit_enter/dpt_free/crit_exit, bus_dma_tag_destroy(parent_dmat); release io with the rid it was allocated at (io_rid).
Verdict
Line-proven incomplete error-path unwind in dpt_pci_attach(): on bus_setup_intr failure (dpt_pci.c:163-169) the code jumps to bad: releasing only io/irq, while dpt_attach() (called at :159) has already XPT-registered up to 3 SIMs + wildcard CAM paths (dpt_scsi.c:1466-1482), registered the shutdown_post_sync handler with a discarded tag (dpt_scsi.c:1487-1488), and dpt_alloc() TAILQ-linked the softc on the global dpt_softcs (dpt_scsi.c:1165). None of that is undone: the phantom SIM stays resolvable by CAM and pokes bus_space through a handle whose rman record was released (irq, correct rid 0) or leaked (io, the DF-2151 wrong-rid no-op), dptshutdown keeps firing at every reboot against the released window, DMA CCB memory/sg maps/3 child tags leak permanently, and no interrupt handler exists so every command routed to the phantom bus hangs forever. Untested because the entry path is hardware-gated: guest pciconf shows no 0x1044:0xa400 DPT device (env.txt) and no unprivileged trigger exists; ceiling on real hardware is cross-device PIO/MMIO corruption at boot plus boot-time DoS. No kernel-heap primitive, so no uid=0 route - the class does not permit one.
No comments yet.