trm_detach frees I/O port, SRB array and DMA tags before bus_teardown_intr and SIM deregistration, with no drain of in-flight CCBs β use-after-free / permanent CAM wedge on kldunload
Summary
trm_detach releases pACB->iores first, frees SG maps of only the free-list SRBs, frees the entire 256-entry SRB array and all dma tags BEFORE bus_teardown_intr and BEFORE xpt_bus_deregister/cam_sim_free. In-flight CCBs are never xpt_done'd; their ccb_trmsrb_ptr dangles into freed memory; the live interrupt handler can execute against released bus space; CAM can still call trm_action on the freed softc. Root kldunload trm.ko or physical PCI hot-remove while I/O is in flight -> ISR/CAM touch freed SRB array / released MMIO -> UAF panic or leaked CCBs wedging the SIM queue until reboot. Reorder+drain fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3830 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.5 KB | β raw | |
| VERDICT.md | β | 3.0 KB | β raw | |
| verdict.json | β | 2.9 KB | view raw | |
| fix.diff | β | 3.5 KB | view raw | |
| env.txt | β | 1.1 KB | view raw | |
| manifest.json | β | 742 B | view raw |
DF-3830 β trm_detach frees live DMA/bus resources before tearing down the interrupt and deregistering the SIM
- File:
sys/dev/disk/trm/trm.c(pass 2) - Class: CWE-99 / CWE-416 (use-after-free via improper shutdown ordering), missing queue drain
- Severity: Low (trigger requires root
kldunload trm.koβ module not in GENERIC β or physical PCI hot-removal of a Tekram DC395U/U2 adapter while I/O is in flight)
Build / Run / Expected
Not runnable on the audit guest: no Tekram PCI device (see env.txt); trm_probe() only matches
0x03911DE1/0x03921DE1, so the driver never attaches and trm_detach is unreachable there.
On hardware, the trigger is:
kldload trm.ko # card present, disk busy (dd if=/dev/daX of=/dev/null bs=1m) kldunload trm.ko # trm_detach runs with SRBs in flight
Expected on vulnerable code: interrupt storm / kernel panic (NULL or freed pACB->pFreeSRB,
pSRB->pccb), or leaked CCBs wedging the CAM queue β any of which constitutes the UAF.
Root cause (order of operations in trm_detach, trm.c:3692-3716)
bus_release_resource(dev, SYS_RES_IOPORT, ...)β trm.c:3696 β I/O port region RELEASED FIRST, whilepACB->irqis still installed. Any interrupt between here andbus_teardown_intr(trm.c:3710) makestrm_Interruptdobus_space_read/writeon a released region.trm_destroySRB(pACB)β trm.c:3697 β frees SG lists andpSRB->dmamapfor only the SRBs onpACB->pFreeSRB(trm.c:2999-3015). SRBs sitting on per-targetpWaitingSRB/pGoingSRBlists and the activepActiveSRBare NOT visited: their maps leak and β worse βbus_dmamem_free(pACB->srb_dmat, pACB->pFreeSRB, ...)β trm.c:3700 β frees the entire 256-entry SRB array that those in-flight CCBs still reference (ccb_h.ccb_trmsrb_ptr), while theirpccbs are neverxpt_done'd (no drain, no freeze).- Only afterwards:
bus_teardown_intr(3710), thenxpt_bus_deregister/cam_sim_free(3714-3715). Until then CAM still owns a registered SIM whosetrm_actioncan be invoked concurrently against freed softc state (pACB->pFreeSRBnow dangling, dma tags destroyed at 3698/3703/3708/3709 before the SIM that uses them is gone).
Contrast with trm_attach's own error path (trm.c:3631-3665) which at least tears down in the
sensible order (no interrupt/DMA race there because the SIM was never registered on failure).
Fix
Reorder trm_detach: deregister the SIM first (after flushing), tear down the interrupt second,
release DMA memory third, I/O port last. See fix.diff.
VERDICT β DF-3830
status: inconclusive (source-certain, hardware-gated) β reproduced: 0 β impact demonstrated on guest: none (confirmed impact class on hardware: UAF/panic/wedge; not exercised β no Tekram HBA on the audit guest, env.txt).
Why this is a real defect (line-cited trace)
trm_detach (sys/dev/disk/trm/trm.c:3692-3716) executes, in this order:
| step | line | operation | consequence |
|---|---|---|---|
| 1 | 3696 | bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), pACB->iores) |
chip registers unmapped while IRQ still live (teardown at 3710) β ISR (trm_Interrupt, trm.c:1300-1352) touches a released bus space |
| 2 | 3697 | trm_destroySRB(pACB) |
walks only pACB->pFreeSRB (trm.c:3003-3014) β SRBs on pDCB->pWaitingSRB, pDCB->pGoingSRB, pDCB->pActiveSRB keep live sg_dmamap/dmamap |
| 3 | 3698-3709 | destroy sg_dmat, free the whole SRB array (bus_dmamem_free(srb_dmat, pACB->pFreeSRB, β¦), 3700), free sense buffers, destroy buffer_dmat |
every in-flight CCB's ccb_h.ccb_trmsrb_ptr (set at trm.c:588) now dangles; their pccbs are never xpt_done'd (no drain anywhere) β CAM wedge + UAF on next touch |
| 4 | 3710 | bus_teardown_intr(dev, pACB->irq, pACB->ih) |
the ISR could still be running against steps 1-3 state |
| 5 | 3712-3715 | xpt_async(AC_LOST_DEVICE), xpt_free_path, xpt_bus_deregister, cam_sim_free |
the SIM that calls trm_action/trm_poll into the freed softc is only deregistered last |
There is no xpt_freeze_simq, no drain of going/waiting SRBs, no completion of outstanding CCBs β
compare FreeBSD's later trm(4), and the driver's own attach-failure path which never has the
SIM registered while freeing (trm.c:3631-3665).
Reachability
trmis not in X86_64_GENERIC; it is a KLD (sys/dev/disk/trm/Makefile). Trigger: rootkldunload trm.kowith I/O in flight, or surprise hot-removal of the PCI card.- Root-only / physical β severity Low, but the primitive is a straight UAF of the 128 KiB SRB array
(
TRM_MAX_SRB_CNT * sizeof(TRM_SRB), trm.c:3441-3456) plus unmapped-MMIO ISR execution. - Guest:
pciconf -lshows 7 devices, none with vendor 0x1DE1 (env.txt) βtrm_probe(trm.c:3677-3688) returns ENXIO, driver never attaches,trm_detachunreachable. Hence inconclusive rather than reproduced.
Fix validation
fix.diff reorders detach into: flush+deregister SIM β teardown IRQ β free SRB DMA β free sense β destroy tags β release I/O port, and drains going/waiting lists (complete with CAM_UNEXP_BUSFREE, recycle SRB) before freeing the array. Not exercisable on this guest (no hardware); compiles-by-inspection against the current tree only.
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_testableBaseline and patched behavior both require an attached Tekram DC395 adapter; absent on the audit guest. fix.diff is git-apply-able against sys/dev/disk/trm/trm.c (verified) and compiles by inspection.
fix.diff
Confirmed kernel references
Detail
Exploit chain
root-only/physical: kldunload trm.ko (module not in GENERIC) or surprise PCI removal while I/O is in flight -> ISR/CAM touch freed SRB array and released bus space -> UAF panic or leaked CCBs wedging the SIM queue. No unprivileged route.
Evidence (decisive lines)
VERDICT.md (order-of-operations table with line refs); env.txt (guest hardware absence); fix.diff (reordered detach + trm_detach_flush drain, git-apply --check passes)
PoC changes
No runnable PoC exists without the PCI card; pack is analysis + fix only.
Verified recommended fix
Reorder trm_detach: freeze+deregister SIM, drain/complete in-flight CCBs, bus_teardown_intr, then free DMA memory, release IOPORT last (fix.diff).
Verdict
trm_detach (sys/dev/disk/trm/trm.c:3692-3716) releases the chip I/O port FIRST (3696), frees SG maps for only the free-list SRBs (trm_destroySRB, 3697 -> 2999-3015), then frees the entire 256-entry SRB array with bus_dmamem_free (3700) and destroys every dma tag (3698-3709) BEFORE bus_teardown_intr (3710) and BEFORE the SIM is deregistered (xpt_bus_deregister/cam_sim_free, 3714-3715), with no xpt_freeze_simq and no drain: in-flight CCBs are never xpt_done'd, their ccb_h.ccb_trmsrb_ptr dangles into freed memory, the still-registered interrupt can fire into released bus space, and CAM can still call trm_action against the freed softc. kldunload/hot-remove therefore yields a use-after-free and/or permanent CAM wedge. Source-certain; not exercisable on the audit guest because no Tekram PCI device exists (env.txt: pciconf shows 7 QEMU devices, none vendor 0x1DE1), so trm never attaches and detach is unreachable there.
No comments yet.