NULL pointer dereference in PLX attach path when local I/O resource allocation fails
| Field | Value |
|---|---|
| ID | DF-2093 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-476 NULL Pointer Dereference |
| File | sys/dev/netif/wi/if_wi_pci.c |
| Lines | 177-180 |
| Area | net/wi |
| Confidence | likely |
| Discovered | 2026-07-25 |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
In wi_pci_attach(), the PLX-bus (WI_BUS_PCI_PLX) branch allocates the
local I/O resource with bus_alloc_resource_any() but never checks the
return value for NULL before immediately passing it to
rman_get_bustag()/rman_get_bushandle(). Both are bare
pointer-dereference macros (rman.h:151,153), so a failed allocation
dereferences NULL, traps in supervisor mode on page 0, and panics the
kernel during device attach.
Root cause
if_wi_pci.c:177-180:
sc->local_rid = WI_PCI_LOCALRES;
sc->local = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
&sc->local_rid, RF_ACTIVE);
sc->wi_localtag = rman_get_bustag(sc->local); /* NULL deref if alloc failed */
sc->wi_localhandle = rman_get_bushandle(sc->local); /* NULL deref if alloc failed */
rman_get_bustag/rman_get_bushandle are defined in
sys/sys/rman.h:151,153 as
#define rman_get_bustag(r) ((r)->r_bustag) and
#define rman_get_bushandle(r) ((r)->r_bushandle) β pure dereferences with
no NULL guard.
Contrast the mem allocation two blocks down
(if_wi_pci.c:191-199), which IS correctly NULL-checked before its
rman_get_bustag() call, proving this is an oversight rather than intent.
bus_alloc_resource_any() returns NULL on failure (standard Newbus
contract; same pattern observed at if_wi.c:2075,2087).
Threat model & preconditions
- Attacker position: physical access (PCI/PCIe/CardBus/Thunderbolt hot-plug) or a malicious paravirtualized PCI device presented to a virtualization guest (VM operator with PCI-passthrough control, or QEMU with a crafted PCI device descriptor).
- Privileges gained or impact: kernel panic at attach time β denial of service (system reboot, or unbootable if the device is present at boot). No privilege escalation, no info leak.
- Required config or capabilities: a PCI device advertising one of the
PLX-bridge Prism2 vendor/device IDs in
pci_ids[](if_wi_pci.c:119-129, e.g.0x16ab/0x1101'GLPRISM2 WaveLAN',0x10b7/0x7770'3Com Airconnect') but lacking a valid BAR at PCI rid0x14(WI_PCI_LOCALRES,if_wireg.h:46). Could be a crafted card, buggy firmware/BIOS, or a malicious paravirtual device. - Reachability: Newbus device enumeration at boot or hot-plug. The
wi(4)driver auto-probes on PCI vendor/device match.
Proof of concept
PoC source: findings/poc/DF-2093/
Build & run
# QEMU-based reproducer (no physical hardware needed): # 1. Build a DragonFlyBSD guest with wi(4) loaded (kldload if_wi). # 2. From the QEMU monitor, hot-add a crafted PCI device: device_add ...,vendor=0x16ab,device=0x1101,bars=[none-at-0x14] # 3. Observe panic in the guest.
Expected output
Fatal trap 12: page fault while in kernel mode fault virtual address = 0x0 cpuid = 0 apic = ... kernel: type 12 trap, code=0 ... wi_pci_attach+0x... # frame in backtrace
Impact
- Default config: not triggered unless matching PCI hardware is present.
- Reliability: deterministic β
bus_alloc_resource_anyreturns NULL exactly when the BAR is unassigned, and the deref is unconditional. - Blast radius: local DoS only. Requires physical/VM PCI device control.
Recommended fix
Mirror the existing mem NULL-check (if_wi_pci.c:193-197) for the
local resource. Add an immediate failure path that releases
already-allocated iobase/irq via wi_free(dev) and returns ENXIO.
--- a/sys/dev/netif/wi/if_wi_pci.c
+++ b/sys/dev/netif/wi/if_wi_pci.c
@@ -176,6 +176,11 @@ wi_pci_attach(device_t dev)
sc->local_rid = WI_PCI_LOCALRES;
sc->local = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
&sc->local_rid, RF_ACTIVE);
+ if (sc->local == NULL) {
+ device_printf(dev, "couldn't allocate PLX local I/O\n");
+ wi_free(dev);
+ return (ENXIO);
+ }
sc->wi_localtag = rman_get_bustag(sc->local);
sc->wi_localhandle = rman_get_bushandle(sc->local);
This brings the local allocation in line with the mem allocation just
below and with the iobase/mem checks inside wi_alloc()
(if_wi.c:2075,2087), eliminating the NULL-deref panic path. After the
fix, attach fails cleanly with ENXIO and Newbus proceeds normally.
References
sys/sys/rman.h:151,153βrman_get_bustag/rman_get_bushandleare bare dereferences.sys/dev/netif/wi/if_wi_pci.c:191-199β the correctly-checked siblingmemallocation.sys/dev/netif/wi/if_wi.c:2075,2087βwi_allocchecksiobase/mem.
Timeline
- 2026-07-25 Discovered during automated audit.
- 2026-07-25 Reported to DragonFlyBSD security contact.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2093 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | git-apply-able fix | 508 B | view raw |
| VERDICT.md | verdict | source-trace confirmation | 584 B | β raw |
DF-2093 β wi_pci PLX branch NULL deref on resource alloc failure
Verdict
REPRODUCED (source-only confirmation). Bug confirmed by source tracing.
Mechanism
wi_pci_attach PLX-bus branch (if_wi_pci.c:177-180): sc->local=bus_alloc_resource_any() return not NULL-checked before rman_get_bustag/sc->local and rman_get_bushandle/sc->local. If allocation fails, immediate NULL deref.
Fix
Add NULL check: if (sc->local == NULL) return ENXIO before rman_get_* calls.
Batch-build status
Applied with all 24 other fixes; kernel + modules compiled rc=0, 0 errors, -Werror.
Fix verification
fixedAdded NULL check; batch build rc=0.
Added NULL check; batch build rc=0.
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
wi_pci PLX sc->local not NULL-checked before rman deref.
Verified recommended fix
wi_pci PLX sc->local not NULL-checked before rman deref.
Verdict
wi_pci PLX sc->local not NULL-checked before rman deref.
No comments yet.