bt_pci_attach() error unwind after bus_setup_intr() failure leaves an XPT-registered SIM and wildcard CAM path live over released port/IRQ rman records, freed DMA memory and a lockuninit'd softc lock (UAF-class teardown)
Summary
bt_attach registers the CAM bus/path BEFORE setup_intr but its failure branch skips the CAM teardown the two earlier branches perform - the glue then releases everything, leaving the sim's closures pointing at the freed softc: the CAM scan runs on a destroyed lock through released ports into freed DMA memory. The dpt DF-5153 sibling shape. Hardware-gated boot-time trigger. Mirror-the-earlier-branch teardown fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5167 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.1 KB | β raw | |
| VERDICT.md | β | 4.7 KB | β raw | |
| verdict.json | β | 3.4 KB | view raw | |
| fix.diff | β | 726 B | view raw |
DF-5167 β bt: bus_setup_intr() failure in bt_attach leaves XPT-registered SIM and
wildcard path live against a softc whose resources bt_pci_attach() then releases
File: sys/dev/disk/buslogic/bt_pci.c (with root cause in sys/dev/disk/buslogic/bt.c)
Pass 2 (GLM 5.3). Severity: Low. Confidence: certain (static code-path proof).
What breaks
bt_attach() (bt.c:737) registers a CAM SIM and wildcard path before it sets up
the interrupt:
- bt.c:770
xpt_bus_register(bt->sim, 0)β succeeds - bt.c:776
xpt_create_path(&bt->path, ... CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)β succeeds - bt.c:789
bus_setup_intr(dev, bt->irq, INTR_MPSAFE, bt_intr, bt, &bt->ih, NULL)β on failure prints and returns the error at bt.c:792-794 withoutxpt_bus_deregister(),xpt_free_path()orcam_sim_free().
The PCI glue then treats any bt_attach() failure as "nothing was published" and
releases everything (bt_pci.c:152-156):
- bt_pci.c:93-96
bus_release_resource(dev, SYS_RES_IOPORT, BT_PCI_IOADDR, bt->port) - bt_pci.c:97-98
bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq) - bt_pci.c:99 β bt.c:179-236
bt_free_softc(): unloads/frees the mailbox block, the CCB array and every S/G map, destroys all child DMA tags, andlockuninit(&bt->lock)(bt.c:236).
Result: the XPT still owns a registered bt bus whose btaction/btpoll
closures capture the softc. The CAM probe periph reacts to the bus registration
and issues a bus scan; btaction() then:
- runs under
bt->lockβ a lock that has just beenlockuninit()'d; - touches
bt_inb(bt, STATUS_REG)through an rman port record that was already released (and can be re-allocated to a different device on the same ports); - pulls BCCBs from
bt->free_bt_ccbs, which points intobus_dmamem_free()'d memory β a use-after-free read/write path once the pages are reused.
This is the BusLogic sibling of dpt_pci DF-5153 (same family, same pass) and is
distinct from the known bt_pci.c pair DF-2162/DF-2431 (which cover only the
parent_dmat tag leak; this finding is about CAM state + released rman/DMA
memory, a different resource set and failure point).
Trigger / threat
Boot-time only: a real BusLogic MultiMaster PCI HBA must be present and
bus_setup_intr() must fail (interrupt table exhaustion, conflicting MP/ACPI
table entries, ...). Not reachable from an unprivileged user; not controllable
by a hostile card (the failure is host-side). Impact ceiling: panic / kernel
memory corruption during/after boot on that machine. Hence Low.
Verification status
Skipped per contract (Low severity, hardware-preconditioned trigger β the
QEMU guest has no BusLogic PCI HBA, so neither the boot-time failure nor the
card itself can be instantiated). verdict.json carries the persistable status
untested for that reason; the finding is proven by code-path analysis with
exact citations (see VERDICT.md).
Fix
fix.diff β deregister/free the CAM state in bus_setup_intr()'s error branch
in bt.c before returning, mirroring the existing xpt_create_path failure
branch (bt.c:776-783).
DF-5167 β VERDICT
Status: skipped / untested (static proof only). Reproduced: no (not reachable on the audit guest). Classification if triggered: kernel use-after-free class teardown defect, boot-time availability/integrity.
Narrative
The code path, proven line by line
bt_pci_attach()(sys/dev/disk/buslogic/bt_pci.c:118) allocates port + IRQ resources (bt_pci_alloc_resources, bt_pci.c:51-86; IRQ at bt_pci.c:76-77 withRF_ACTIVE | RF_SHAREABLE) and callsbt_init_softc()(bt_pci.c:83 β bt.c:163), which storesbt->port,bt->irqandlockinit(&bt->lock)(bt.c:175).bt_pci_attach()then runsbt_probe() || bt_fetch_adapter_info() || bt_init()(bt_pci.c:147).bt_init()(bt.c:580-735) raisesbt->init_levelto 8, allocating the mailbox block, the CCB array, S/G maps and five child DMA tags.bt_attach()(bt.c:737) then: - bt.c:770:xpt_bus_register(bt->sim, 0)β the XPT now owns the bus; - bt.c:776:xpt_create_path(&bt->path, NULL, ..., CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - bt.c:789-794:bus_setup_intr()β on failure:device_printf+return (error)with NOxpt_bus_deregister(), NOxpt_free_path(), NOcam_sim_free(). (Contrast the two earlier failure branches at bt.c:770-774 and 776-783, which deregister and free the sim β the last branch simply forgot.)bt_pci_attach()sees the error (bt_pci.c:152-156) and callsbt_pci_release_resources()(bt_pci.c:88-100): - releases the IOPORT rman record (bt_pci.c:95-96), - releases the IRQ rman record (bt_pci.c:97-98), -bt_free_softc()(bt.c:179-236): unload/free mailbox + CCB array + all S/G maps, destroy all child DMA tags,lockuninit(&bt->lock)(bt.c:236).
Why the leftover state is dangerous
The registered SIM's btaction/btpoll closures capture bt (softc pointer,
bt.c:764-765 cam_sim_alloc(btaction, btpoll, "bt", bt, ...)). After step 4 the
CAM layer (probe periph reacting to the bus registration; any later XPT request
on the wildcard path bt->path) can still invoke btaction(), which:
- is entered under the sim lock
&bt->lock(a destroyed lock object), - reads card registers through the released port resource (on re-allocation of those ports to another driver this becomes cross-device register access),
- executes
btgetccb()(bt.c:870) poppingbt->free_bt_ccbsβ a list embedded inbus_dmamem_free()'d memory (bt.c:192-232 case 6/8 ofbt_free_softc), and writes CCB state there β use-after-free read/write.
The init_level ladder in bt_free_softc (bt.c:183-236) pairs every init_level++
in bt_init (bt.c:625,642,650,659,682,690,698,714 β max level 8; cases 9-11 for
sense buffers are dead code in this driver), so the DMA unwind itself is
complete except parent_dmat β that omission is the known DF-2162/DF-2431
pair and is intentionally not re-reported here. This finding is the other
half of the unwind that is broken: the CAM registration done by bt_attach().
Why it was not reproduced on the guest
- Requires a physical BusLogic MultiMaster PCI HBA (VID 0x104B, DID 0x1040/0x0140, bt_pci.c:47-48,105-107) present in the machine.
- Requires the host-side
bus_setup_intr()to fail at boot β not attacker- or card-controllable. - The QEMU audit guest has no such device; the failure point cannot be reached by any local program. Per the audit contract, Low/hardware-preconditioned findings skip the QEMU phase.
Family calibration (same pass)
- dpt_pci DF-5153 (Low, CWE-459): identical shape, additionally left a shutdown handler and global softc list entry live.
- adv_pci DF-5043 (Low): the "IRQ resource left allocated" variant β not applicable to bt, whose glue does release the IRQ (bt_pci.c:97-98).
- adv_pci DF-5042 / dpt_pci DF-5154 = the
parent_dmatleak family = bt's known DF-2162/DF-2431 (not re-reported).
Bottom line
Certain-by-inspection boot-time teardown defect: the last error branch of
bt_attach() leaks the CAM registration, and the PCI glue's unconditional
resource release then pulls the port/IRQ records, the DMA memory and the softc
lock out from under the still-registered SIM β a UAF-class hazard bounded by the
rare trigger (vintage PCI HBA + IRQ-setup failure at boot), so Low severity,
no userland attack path, not testable on the audit guest.
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 statically against the read-only sys/ tree after line-accurate confirmation of the root cause; not built or run because the trigger hardware does not exist on the audit guest (verification was skipped for the same reason).
findings/poc/DF-5167/fix.diff (git-apply-able unified diff vs sys/dev/disk/buslogic/bt.c; never applied to sys/)
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-5167/VERDICT.md (full line-cited proof); bt_pci.c:152-156 -> bt_pci.c:88-100 -> bt.c:179-236 (release side); bt.c:770-794 (the branch that leaks the CAM registration); README.md for the family calibration
PoC changes
No PoC exists: the trigger requires a physical BusLogic MultiMaster PCI HBA (VID 0x104B DID 0x1040/0x0140, bt_pci.c:47-48) plus a boot-time bus_setup_intr() failure; neither can be instantiated on the QEMU guest. Static-analysis evidence pack only.
Verified recommended fix
In bt_attach()'s bus_setup_intr() error branch, xpt_free_path + xpt_bus_deregister + cam_sim_free under bt->lock before returning (see fix.diff), mirroring the existing xpt_create_path failure branch at bt.c:776-783.
Verdict
Skipped per contract (Low severity, hardware-preconditioned boot-time trigger): proving it by code inspection only. bt_attach()'s bus_setup_intr() failure branch (bt.c:789-794) returns without deregistering the XPT bus registered at bt.c:770 or freeing the wildcard path/sim created at bt.c:776; bt_pci_attach() (bt_pci.c:152-156) then calls bt_pci_release_resources(), which releases the port and IRQ rman records (bt_pci.c:93-98) and bt_free_softc() unloads/frees the mailbox block, CCB array, S/G maps and lockuninit's bt->lock (bt.c:179-236). The still-registered SIM's btaction/btpoll closures capture the softc, so the CAM probe periph's bus scan reaches a destroyed lock, released port resources and bt->free_bt_ccbs living in bus_dmamem_free()'d memory - a UAF-class teardown hazard, reachable only at boot with a real BusLogic PCI HBA whose interrupt setup fails. Not reachable on the QEMU audit guest (no such PCI device, not user-controllable). Distinct from known DF-2162/DF-2431 (parent_dmat tag leak only); sibling of dpt_pci DF-5153.
No comments yet.