β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3923

hpt_attach bus_setup_intr failure kfree()s the newbus-owned IAL_ADAPTER_T softc while it stays linked on gIal_Adapter (use-after-free)

Summary

On IRQ-setup failure the driver frees device_get_softc() memory that newbus owns and never unlinks the adapter from the global gIal_Adapter list (nor undoes init_adapter's interrupt unmask) - later gIal_Adapter walks (ioctls, rescan, worker) and newbus softc reuse dereference freed memory. Attach-time IRQ failure on a present RR1820 (e.g. passthrough VM with exhausted IRQs). Drop-the-kfree fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3923 Β· 6 files
FileTypeDescriptionSize
README.md β€” 2.0 KB ↓ raw
VERDICT.md β€” 1.7 KB ↓ raw
fix.diff β€” 310 B view raw
env.txt β€” 1.2 KB view raw
manifest.json β€” 803 B view raw
verdict.json β€” 1.8 KB view raw

DF-3923 β€” hpt_attach failure path kfree()s the newbus-owned softc and leaves the freed adapter globally linked

What

sys/dev/raid/hptmv/entry.c:2022-2028 (hpt_attach):

if (bus_setup_intr(pAdapter->hpt_dev, pAdapter->hpt_irq, 0,
            hpt_intr, pAdapter, &pAdapter->hpt_intr, NULL))
{
    hpt_printk(("can't set up interrupt\n"));
    kfree(pAdapter, M_DEVBUF);      /* <-- frees softc owned by newbus */
    return(ENXIO);
}

For a PCI driver the softc (sizeof(IAL_ADAPTER_T), driver_t at entry.c:97-101) is embedded in the newbus device and returned by device_get_softc(dev) (entry.c:1992) β€” it is NOT a driver allocation. init_adapter() (called at entry.c:2011, succeeding) has already: - linked pAdapter into the global gIal_Adapter list (entry.c:1280-1287), - started the MV core (mvSataInitAdapter, entry.c:1349), - unmasked adapter interrupts (entry.c:1498).

After the kfree: the device still exists with a dangling softc; gIal_Adapter still points at freed memory. Any later walk of that list β€” hptproc ioctls (Kernel_DeviceIoControl, DF-1853 family), RESCAN_DEVICES (ioctl.c:302), worker-thread SIGSTOP walk (entry.c:2438-2456) β€” dereferences freed memory. Newbus itself touches the freed softc on device state changes (probe cycle, detach, shutdown). Additionally the earlier IRQ-allocation failure path (entry.c:2016-2020) returns without unlinking the adapter or releasing mem_res, leaking a half-initialized adapter with interrupts unmasked.

Error-path gated (requires bus_setup_intr/bus_alloc_resource failure on a present RR1820 β€” e.g. IRQ shortage in a passthrough VM), hardware-gated, but a genuine use-after-free of kernel memory once hit.

Fix

--- a/sys/dev/raid/hptmv/entry.c
+++ b/sys/dev/raid/hptmv/entry.c
@@ -2023,7 +2023,6 @@ hpt_attach(device_t dev)
 {
    hpt_printk(("can't set up interrupt\n"));
-   kfree(pAdapter, M_DEVBUF);
    return(ENXIO);
 }

plus proper teardown in init_adapter's caller (unlink from gIal_Adapter, release mem_res/irq) β€” see fix.diff.

VERDICT.md
↓ download raw

DF-3923 VERDICT

status: not_reproduced (hardware-gated error path) | impact observed: none (potential: UAF of kernel memory) | source certainty: likely

Trace

  • entry.c:1992 IAL_ADAPTER_T *pAdapter = device_get_softc(dev); β€” newbus softc (driver_t size entry.c:100); only kmalloc'd if softc were NULL (entry.c:2000-2004), which never happens for an attached PCI device.
  • entry.c:2011 init_adapter succeeds β†’ adapter linked into gIal_Adapter (entry.c:1280-1287), MV core initialized, interrupts unmasked (entry.c:1498).
  • entry.c:2026 kfree(pAdapter, M_DEVBUF) on bus_setup_intr failure frees memory newbus still owns; gIal_Adapter list retains the dangling pointer (no unlink anywhere on this path).
  • Consumers of gIal_Adapter: ioctl.c:302 (RESCAN_DEVICES walk), hptproc.c/Kernel_DeviceIoControl, entry.c:2438-2456 (worker SIGSTOP walk), launch_worker_thread (entry.c:2486). Newbus also reuses the softc on the next probe of the same devclass unit.

Why not reproduced

Needs a present RR1820 whose IRQ setup fails at attach β€” no such hardware on the audit guest (env.txt). Confidence "likely": the double-ownership/free is unambiguous, but reaching it requires a specific attach failure on real hardware.

Fix validation

Not possible without the controller. fix.diff removes the erroneous kfree and adds teardown.

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_testable
baseline no→ patch + rebuild →patched clean

fix.diff removes the erroneous kfree and releases resources; cannot validate without hardware

fix.diff in this pack; never applied to sys/
↓ fix.diffper-fix-DF-3923

Confirmed kernel references

Detail

Exploit chain

IRQ setup failure at attach -> freed softc dangling on gIal_Adapter + newbus device -> later ioctl/rescan/probe UAF (crash-class, privileged contexts)

Evidence (decisive lines)

VERDICT.md ownership trace (entry.c:1992 vs 2026; 1280-1287 link)

PoC changes

n/a (fresh pack)

Verified recommended fix

Drop the kfree of the newbus softc and release the IRQ resource on failure

Verdict

On bus_setup_intr failure hpt_attach kfree()s pAdapter (entry.c:2026) which is the newbus-allocated softc (device_get_softc, entry.c:1992; driver_t size entry.c:100) - not driver memory. init_adapter already linked it into gIal_Adapter (entry.c:1280-1287) and unmasked interrupts (entry.c:1498), so post-failure any gIal_Adapter walk (ioctl.c:302, hptproc, worker entry.c:2438-2456) or newbus softc reuse dereferences freed memory. Requires an attach-time IRQ failure on real RR1820 hardware; not reproducible on the audit guest.