dpt_pci_attach() leaks parent_dmat on the dpt_init() failure path β dpt_free()'s init_level ladder never destroys the DMA tag the PCI glue created
Summary
Split ownership: the glue creates parent_dmat, common-code dpt_free unwinds only dpt_init state, nobody owns the destroy (rg-exhaustive) - one tag leaks per failed attach. One-line destroy-after-free fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5154 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.5 KB | β raw | |
| VERDICT.md | β | 3.2 KB | β raw | |
| fix.diff | β | 427 B | view raw | |
| verdict.json | β | 2.9 KB | view raw | |
| env.txt | β | 992 B | view raw |
DF-5154 β dpt_pci_attach() leaks parent_dmat on the dpt_init() failure path (dpt_free() never destroys the glue's DMA tag)
File: sys/dev/raid/dpt/dpt_pci.c:134-156
Class: resource leak on error path (CWE-401)
Severity: Info (one-shot, hardware-gated, boot/kldload-time only)
Distinct from DF-2151 (known, not re-reported): DF-2151 is the wrong-rid
bus_release_resource; this is the DMA-tag lifecycle gap. Also distinct from
DF-5153 (the bus_setup_intr-failure unwind): that path additionally leaks
parent_dmat too, but this finding is the one that fires even on the
earlier, otherwise-correct dpt_init failure path where dpt_free is
called.
The bug
The PCI glue creates the parent DMA tag (dpt_pci.c:134-143):
if (bus_dma_tag_create(/*parent*/NULL, ..., &dpt->parent_dmat) != 0) {
dpt_free(dpt);
error = ENXIO;
goto bad;
}
...
if (dpt_init(dpt) != 0) { /* dpt_pci.c:151 */
dpt_free(dpt); /* <-- frees children only */
error = ENXIO;
crit_exit();
goto bad;
}
dpt_free (dpt_scsi.c:1172-1204) unwinds exactly the objects dpt_init
created, stepping init_level 5β0: dccb_dmamap unload/free/destroy,
dccb_dmat, buffer_dmat, the sg-map list and sg_dmat. It never touches
parent_dmat β the tag the glue created before dpt_init ran. rg
parent_dmat sys/dev/raid/dpt/ shows the full picture: created once
(dpt_pci.c:143), consumed as the parent of the three child tags
(dpt_scsi.c:1235/1356/1370), destroyed nowhere. On the dpt_init
failure path the tag (and its reference on the bus DMA machinery) leaks
permanently. The success path never destroys it either β but there the
driver intentionally keeps it for the device lifetime (there is no detach
method at all), so only the error path is a defect.
Impact
Bounded: one bus_dma_tag_t + policy copy leaked per failed attach of a DPT
0x1044:0xa400 controller. Requires the real HBA present and dpt_init
failing (board config handshake failure, DMA tag creation failure inside
dpt_init, CCB allocation failure). No unprivileged trigger; no memory-safety
consequence; correctness/hygiene only. Filed as hardening completeness so
the family's teardown story is whole (mlx/ips/ida/amr/mfi siblings each got
their unwind findings this pass).
Fix
fix.diff: destroy parent_dmat after dpt_free(dpt) on the
dpt_init-failure path (child tags are destroyed by dpt_free, so the
parent destroy afterwards is legal). DF-5153's fix performs the same
destroy on the later bus_setup_intr-failure path.
DF-5154 VERDICT β parent_dmat leak on dpt_init failure
Status: untested (hardware-gated β no DPT controller on the audit
guest, pciconf -l shows no 0x1044 device; see env.txt).
Impact: none demonstrable on the guest β the defect itself is
line-proven (confidence: certain), the impact is a bounded boot-time
resource leak on real hardware only.
Fix: authored (fix.diff, applies clean via git apply --check); fix
validation not_testable (baseline cannot be reproduced without the HBA).
1. Root cause (line-certain)
sys/dev/raid/dpt/dpt_pci.c:134-143β glue createsdpt->parent_dmat(parent NULL, i.e. rooted at the bus's own tag).sys/dev/raid/dpt/dpt_pci.c:151-156β ondpt_initfailure the glue callsdpt_free(dpt)and returns;parent_dmatis never destroyed.sys/dev/raid/dpt/dpt_scsi.c:1172-1204βdpt_freeteardown ladder (init_level5β0) destroysdccb_dmamap/dccb_dmat/buffer_dmat/ sg-maps/sg_dmatβ all objects dpt_init created.parent_dmatwas created by the glue beforedpt_init, anddpt_freeis common code shared with no other glue in this tree (dpt_pci.c is the only caller of dpt_alloc/dpt_free insys/dev/raid/dpt/), so the omission is simply a split-responsibility bug: nobody owns the destroy.- Exhaustive reference check:
rg -n parent_dmat sys/dev/raid/dpt/β creation (dpt_pci.c:143), three child-tag uses (dpt_scsi.c:1235, :1356, :1370), softc declaration (dpt.h:986). Nobus_dma_tag_destroyof it anywhere.
2. Reachability / threat model
Requires a DPT SmartRAID PCI HBA (probe match at dpt_pci.c:61-66) and a
dpt_init failure (config handshake via dpt_get_conf, DMA tag/CCB/sg-map
allocation failures β several are device-fed, cf. DF-4245). Both conditions
are boot/kldload-time; no unprivileged trigger, no user-controllable
input, no kernel-memory consequence β the leak is a bus_dma_tag_t plus
policy state per failed attach. Severity Info; would be Low only if a
repeat-attach loop were possible (newbus does not retry failed attaches).
3. Why untested
Same hardware gating as DF-5153: the guest has no DPT device, so the path
cannot be entered even by a KLD harness without fabricating the entire HBA
config handshake (which would demonstrate nothing beyond the code text β
the leak is directly readable from the source: create-without-destroy).
Family precedent: DF-5115 (untested, analysis-verified).
4. Fix
fix.diff β bus_dma_tag_destroy(dpt->parent_dmat) after dpt_free(dpt)
on the dpt_init-failure path; ordering is legal because dpt_free has
already destroyed the three child tags. git apply --check clean against
the audited tree.
5. Kernel references
sys/dev/raid/dpt/dpt_pci.c:134-143, :151-156; sys/dev/raid/dpt/dpt_scsi.c:1172-1204, :1235, :1356, :1370; sys/dev/raid/dpt/dpt.h:986.
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; git apply --check clean (single hunk, dpt_pci.c:150-156). Baseline not reproducible on the guest (no DPT HBA) so patched-kernel validation is not_testable.
findings/poc/DF-5154/fix.diff; VERDICT.md section 4.
Confirmed kernel references
Detail
Evidence (decisive lines)
README.md (create-without-destroy trace), VERDICT.md section 1 (exhaustive rg reference check), fix.diff (git-apply-clean one-hunk destroy after dpt_free), env.txt. Decisive lines: sys/dev/raid/dpt/dpt_pci.c:143 vs dpt_scsi.c:1174-1202 switch ladder with no parent_dmat case.
PoC changes
no seed PoC existed; none authored - path unreachable without DPT hardware; the leak is directly readable from source (create without destroy), a harness would add nothing
Verified recommended fix
bus_dma_tag_destroy(dpt->parent_dmat) immediately after dpt_free(dpt) on the dpt_init-failure path (child tags already destroyed by dpt_free, so the ordering is legal).
Verdict
Line-proven DMA-tag leak: dpt_pci_attach creates dpt->parent_dmat (dpt_pci.c:134-143) before dpt_init, but dpt_free's init_level teardown ladder (dpt_scsi.c:1172-1204) destroys only the objects dpt_init created (dccb/sg/buffer tags, sg maps, CCB DMA memory) - parent_dmat is destroyed nowhere in the driver (rg: created once at dpt_pci.c:143, consumed at dpt_scsi.c:1235/1356/1370, no bus_dma_tag_destroy call). On the dpt_init failure path (dpt_pci.c:151-156) the tag leaks permanently per failed attach. Untested: hardware-gated (guest pciconf has no 0x1044:0xa400 device, env.txt), no unprivileged trigger, no memory-safety consequence - bounded boot-time resource leak only. Info hardening completeness for the raid-family teardown story.
No comments yet.