tws_attach error unwinds leak the MSI allocation and every post-probe resource (~200 KB heap + DMA maps/tags + scan_ccb per failed attach)
Summary
The attach_fail unwinds release only the cdev/IRQ/BARs - never pci_release_msi (detach does, proving the omission) and never reqs/sense_bufs/scan_ccb/aen_q/trace_q/per-req maps/cmd DMA/three tags. ~200KB + an MSI vector per failed attach; failure is most reachable with wedged firmware (the DF-1924/1925 state) where operators retry load/unload - unbounded aggregate leak. Release-everything-in-unwind fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4591 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.9 KB | β raw | |
| VERDICT.md | β | 3.4 KB | β raw | |
| trigger.sh | β | 2.0 KB | view raw | |
| run.sh | β | 250 B | view raw | |
| run.log | β | 425 B | view raw | |
| build.log | β | 212 B | view raw | |
| env.txt | β | 209 B | view raw | |
| guest_probe.log | β | 677 B | view raw | |
| fix.diff | β | 3.3 KB | view raw | |
| manifest.json | β | 1.1 KB | view raw | |
| verdict.json | β | 3.6 KB | view raw |
DF-4591 β tws(4) attach-failure unwinds leak MSI vectors and all post-probe allocations
Finding file: sys/dev/raid/tws/tws.c (pass 2) Lines: 309-341 (attach_fail_4/3/2/1) vs allocations at 202 (trace_q), 426 (MSI), 465-530 (bus_dma tags + dma_mem/cmd_map), 535-539 (reqs, sense_bufs, scan_ccb), 580-581 (aen_q), 610 (per-req dma maps).
What the bug is
tws_detach() carefully releases the MSI allocation
(if (sc->intr_type == PCI_INTR_TYPE_MSI) pci_release_msi(...) β
tws.c:381-382), but the attach-failure unwinds never do. MSI vectors are
allocated as early as tws_setup_irq() β pci_alloc_1intr() (tws.c:426),
i.e. before every attach_fail_4 exit (tws_init / tws_init_ctlr /
tws_cam_attach failure β realistic with wedged firmware per DF-1924/1925,
or per DF-4402's cam attach bugs) and before the bus_setup_intr failure
return at 432-436 (which unwinds at attach_fail_3).
The unwinds also free none of:
- sc->reqs (kmalloc at 535) and sc->sense_bufs (537),
- sc->scan_ccb (xpt_alloc_ccb at 539),
- sc->aen_q.q (580) and sc->trace_q.q (592 β allocated at tws_attach:202,
so even the earliest
goto attach_fail_1at 218-221 leaks it), - the per-request
bus_dmamap_createmaps (610), - the command DMA map/memory (499-509) and the three bus_dma tags (parent/cmd/data, 465-530).
Each failed attach leaks β200 KB of M_TWS kernel heap + DMA resources +
one MSI vector. tws_init() returns FAILURE at 541-543 whenever the
controller fails tws_ctlr_ready()/tws_ctlr_reset() β precisely the
flaky-hardware situation in which an operator retries load/unload cycles,
so the leak is repeatable and unbounded in aggregate. (tws_detach also
never frees the maps/tags/dma_mem β same cleanup gap, included in fix.diff.)
Preconditions / reachability
Requires a 3ware 9700-series controller (13C1:1010) that fails to initialize + root privilege to (re)load the driver. Severity Low.
Reproduce (hardware required)
See trigger.sh. EXPECTED vulnerable: after each failed load,
vmstat -m | grep twsbuf shows the ~200 KB still allocated; repeated
cycles grow it linearly; MSI leak visible via pciconf/devinfo. Patched:
allocation-neutral.
On the audit guest: no 3ware controller (run.log / env.txt) β not_reproduced; defect certain from source (side-by-side with the symmetric, correct code in tws_detach:381-382 / 398-402).
Build / run on guest
./run.sh # probes guest hardware; records absence in run.log
Fix
fix.diff: attach_fail_4 cancels callouts and calls pci_release_msi before destroy_dev; attach_fail_1 frees every guarded allocation (maps β reqs β sense β scan_ccb β aen_q β trace_q β dma map/mem β data/cmd/parent tags); tws_detach gains the missing map/tag/dma_mem cleanup.
DF-4591 VERDICT β not_reproduced (hardware-gated), defect certain from source
Finding
The attach-failure unwinds of tws_attach() (sys/dev/raid/tws/tws.c:309-341)
release only the char device (315-316), the IRQ resource (318-322) and the
memory BARs (326-335). They leak:
- MSI vectors β allocated by
pci_alloc_1intr()insidetws_setup_irq()(tws.c:426) before any attach_fail_4/3 exit;pci_release_msi()exists only in tws_detach (tws.c:381-382), proving the authors knew the release was required and omitted it on the error path. Exits affected:bus_setup_intrfailure (432-436),tws_initFAILURE incl.tws_ctlr_resetfailure (289-292, 541-543),tws_init_ctlrFAILURE (293-296),tws_cam_attacherror (297-300). - Kernel heap β
sc->reqs(kmalloc at :535),sc->sense_bufs(:537),sc->scan_ccb(:539),sc->aen_q.q(:580), andsc->trace_q.qβ the trace queue is allocated at tws_attach:202, before the earliest failure label, so every failed attach leaks it. - DMA resources β per-request maps from
bus_dmamap_create(tws_init_reqs :610), the command DMA map + memory (:499-509), and the parent/cmd/data bus_dma tags (:465-530). (tws_detach likewise never frees the maps/tags/dma_mem β same gap, fixed together.)
Aggregate β200 KB M_TWS heap + DMA resources + 1 MSI vector per failed
attach. The failure is most reachable exactly when hardware is flaky
(tws_init returns FAILURE at :541-543 when tws_ctlr_ready() fails and
tws_ctlr_reset() fails β the DF-1924/DF-1925 wedged-controller state),
i.e. during operator load/unload retry loops β unbounded repeatable leak.
Reproduction attempt on the audit guest
- Guest: DragonFly 6.5-DEVELOPMENT X86_64_GENERIC (env.txt).
- run.sh / run.log / guest_probe.log: no LSI 3ware (0x13C1) PCI device;
tws compiled into the kernel,
dev.twsabsent, no /dev/tws β the attach path never runs, so the leak cannot manifest: status not_reproduced, reproduced=0, impact none (not manifested here)*. Realistic impact ceiling on real hardware: permanent kernel memory / MSI-vector exhaustion via repeated failed loads (privileged, root trigger; Low severity).
Confidence: certain β the asymmetry with tws_detach:381-382/398-402 is mechanical; every leaked allocation is cited to its exact line.
Fix validation
fix.diff: attach_fail_4 gains callout cancellation + pci_release_msi;
attach_fail_1 frees every guarded allocation in reverse order (maps β
reqs β sense_bufs β scan_ccb β aen_q β trace_q β cmd dma map/mem β
data/cmd/parent tags); tws_detach gains the missing map/tag/dma_mem
cleanup. git apply --check passes. Baseline vs patched cannot be
exercised on this guest (no 3ware HW) β fix_status: not_testable;
validated by inspection.
Artifacts
- trigger.sh β failed-attach load-cycle recipe + leak observation points
- run.sh, run.log, guest_probe.log, env.txt β guest hardware-absence proof
- fix.diff β error-unwind cleanup (git-apply clean, self-contained)
- manifest.json / verdict.json
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 not validated on guest: baseline cannot run (no 3ware controller). fix.diff is git-apply clean and mirrors the cleanup tws_detach already performs for the same resources; validated by inspection.
findings/poc/DF-4591/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (allocation-vs-unwind line map with the detach:381-382/398-402 symmetry proof); trigger.sh (failed-attach load-cycle recipe + vmstat observation points); run.log/env.txt/guest_probe.log (no 3ware HW on guest); fix.diff (guarded cleanup of maps/reqs/sense/scan_ccb/aen_q/trace_q/dma map+mem/3 tags in attach_fail_1 + pci_release_msi in attach_fail_4 + detach-side map/tag cleanup; git-apply clean)
PoC changes
No seed pack existed; trigger authored as documented failed-attach recipe plus guest hardware-absence probe.
Verified recommended fix
Release the MSI allocation in the attach-failure unwinds and free every guarded allocation (maps, reqs, sense_bufs, scan_ccb, aen_q, trace_q, cmd DMA map/mem, bus_dma tags) - see fix.diff.
Verdict
The attach-failure unwinds of tws_attach() (tws.c:309-341) release only the cdev, IRQ resource and BARs. They (1) never call pci_release_msi() for the MSI allocation made in tws_setup_irq() (tws.c:426) even though tws_detach() does exactly that at tws.c:381-382 - direct evidence the release was known-required and omitted on the error path; and (2) free none of sc->reqs (535), sc->sense_bufs (537), sc->scan_ccb (539), sc->aen_q.q (580), sc->trace_q.q (allocated at tws_attach:202, leaked even by the earliest attach_fail_1 exit), the per-request bus_dmamap_create maps (610), the command DMA map/memory (499-509) or the three bus_dma tags (465-530). Every failed attach leaks ~200 KB of M_TWS kernel heap + DMA resources + one MSI vector, and failure is most reachable exactly with flaky hardware (tws_init FAILURE at 541-543 when the controller fails tws_ctlr_ready/tws_ctlr_reset - the DF-1924/1925 wedged-controller state) where operators retry load/unload cycles. tws_detach() also never frees the maps/tags/dma_mem (same cleanup gap, included in fix.diff). Not reproduced on the audit guest: no 3ware 13C1:1010 device exists (run.log/env.txt/guest_probe.log; vmstat -m shows no twsbuf; dev.tws absent), and QEMU cannot emulate the controller. Defect certain from source by the detach/error-path asymmetry.
No comments yet.