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

sn_attach() ignores sn_activate() failure: rman_get_cpuid(NULL) guaranteed kernel panic during attach, plus register writes into ISA DMA-controller ports 0x00-0x0F

Summary

sn_attach discards sn_activate's return (the probe path checks the identical call - the asymmetry). On any attach-time resource failure, port_res/irq_res are NULL and BASE is 0: the bank selects/revision/config/MAC writes all land inside the primary 8237 ISA DMA-controller register range, and ifq_set_cpuid(rman_get_cpuid(NULL)) dereferences NULL twice - guaranteed panic during DEVICE_ATTACH. Later sninit would scribble further over ports 0x00-0x0F. Propagate-the-error fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4354 Β· 6 files
FileTypeDescriptionSize
README.md β€” 2.5 KB ↓ raw
VERDICT.md β€” 4.6 KB ↓ raw
fix.diff β€” 229 B view raw
env.txt β€” 818 B view raw
verdict.json β€” 3.4 KB view raw
manifest.json β€” 1.1 KB view raw

DF-4354 β€” sn_attach() ignores sn_activate() failure β†’ rman_get_cpuid(NULL) kernel panic + stray I/O to ISA DMA-controller ports

File: sys/dev/netif/sn/if_sn.c Verdict status: untested β€” hardware-gated (SMC91xx ISA/PCMCIA NIC absent from the QEMU guest; driver is optional sn pccard-only module). Source-level certainty: certain. Class: CWE-252 (unchecked return value) β†’ CWE-476 (NULL pointer dereference in kernel) + stray port I/O.

Where

  • sys/dev/netif/sn/if_sn.c:164 β€” sn_attach() calls sn_activate(dev); and discards the return value.
  • sys/dev/netif/sn/if_sn.c:1170-1192 β€” sn_activate() returns ENOMEM with sc->port_res == NULL, sc->irq_res == NULL, and sc->sn_io_addr never assigned (newbus softc is allocated with M_ZERO, so BASE (sc->sn_io_addr, if_snreg.h:400) is 0).
  • sys/dev/netif/sn/if_sn.c:173-188 β€” with BASE=0 the attach path performs outw(0x0E,3) (SMC_SELECT_BANK(3)), inw(0x0A) (REVISION), inw(0x00) (CONFIG), and β€” when pccard_enaddr is set β€” outw(0x04/0x06/0x08, mac_word). Ports 0x00-0x0F are the primary 8237 ISA DMA controller registers (channel address/count + command/status), NOT this NIC.
  • sys/dev/netif/sn/if_sn.c:216 β€” ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq_res)); with irq_res == NULL. rman_get_cpuid is ((r)->r_rm->rm_cpuid) (sys/sys/rman.h:157) β€” a double dereference of NULL β†’ guaranteed kernel panic during device attach.

Trigger

Any sn_activate() failure inside sn_attach(): I/O port range or IRQ that was allocatable during sn_probe() (which activates, then deactivates at if_sn.c:1318-1321) is no longer allocatable at attach time — resource conflict on the pccard CIS entry, IRQ claimed by another driver in the probe→attach window, or bus_setup_intr-adjacent resource exhaustion. The driver then proceeds to attach against NULL resources.

Fix

--- a/sys/dev/netif/sn/if_sn.c
+++ b/sys/dev/netif/sn/if_sn.c
@@ -161,7 +161,10 @@ sn_attach(device_t dev)
    int     j;
    int     error;

-   sn_activate(dev);
+   error = sn_activate(dev);
+   if (error)
+       return (error);

    snstop(sc);

Reproduce

Not runnable: the QEMU guest has no SMC 91xx hardware and the driver is a module (sys/conf/files:1247 β€” dev/netif/sn/if_sn.c optional sn; front-end is pccard-only, sys/dev/netif/sn/if_sn_pccard.c:106). Guest check performed and recorded in env.txt (ifconfig -l shows only vtnet0 lo0; no sn module loaded; 0 SMC PCI devices). Source-level proof is in VERDICT.md.

VERDICT.md
↓ download raw

DF-4354 β€” VERDICT

Status: untested (hardware-gated) Β· Source-level confidence: certain Β· Expected on real hardware: kernel NULL-deref panic at device attach; collateral stray writes to ISA DMA-controller ports.

Root cause (path:line)

  1. sn_attach() at sys/dev/netif/sn/if_sn.c:164 invokes sn_activate(dev) without checking the return value. Compare sn_probe() at if_sn.c:1236-1237, which does check it (if ((err = sn_activate(dev)) != 0) return err;).
  2. sn_activate() (if_sn.c:1166-1193) can fail after either resource allocation: - bus_alloc_resource(... SYS_RES_IOPORT ...) failure β†’ returns ENOMEM at if_sn.c:1177 with sc->port_res == NULL; - bus_alloc_resource_any(... SYS_RES_IRQ ...) failure β†’ returns ENOMEM at if_sn.c:1188 (port already released by sn_deactivate), sc->irq_res == NULL. In both cases sc->sn_io_addr is never written (if_sn.c:1191 is only reached on success). The newbus softc is zero-allocated (M_ZERO in devclass_alloc_device), so BASE macro (sc->sn_io_addr, sys/dev/netif/sn/if_snreg.h:400) evaluates to 0.
  3. Attach continues: - if_sn.c:173 SMC_SELECT_BANK(3) β†’ outw(0x0E, 3) β€” port 0x0E is the ISA DMA controller (8237) write-request/chain-mask register; - if_sn.c:174 rev = inw(0x0A) β€” reads DMA ch2 word count as "chip revision"; the value then feeds chip_ids[(rev>>4)&0xF] (the DF-1552 OOB-print issue, now reachable at attach with pure garbage); - if_sn.c:179 i = inw(0x00) β€” DMA ch0 address register; - if_sn.c:182-189 (when sc->pccard_enaddr) outw(0x04, w), outw(0x06, w), outw(0x08, w) β€” writes the MAC address into the DMA ch1/ch2 address registers; - any later sninit() (if_sn.c:268 outw(BASE+CONFIG_REG_W, flags) = outw(0x00, flags), if_sn.c:248 outw(BASE+RECV_CONTROL_REG_W, RCR_SOFTRESET), etc.) scribbles further over the DMA controller / PIC-adjacent low ports.
  4. The deterministic crash: if_sn.c:216 ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq_res)); with sc->irq_res == NULL. rman_get_cpuid(r) expands to ((r)->r_rm->rm_cpuid) (sys/sys/rman.h:157) β€” an immediate NULL-pointer dereference in kernel mode during DEVICE_ATTACH, before the error path at if_sn.c:221-224 could ever run.

Why it is a real (if narrow) finding

  • It is an error-path asymmetry of exactly the kind pass 2 hunts: the probe path checks the same call, the attach path does not.
  • Impact ceiling on real hardware: kernel panic at boot/card-insertion time (availability), plus undefined low-port I/O side effects on the ISA DMA controller (system instability). Reachability requires a resource-allocation failure at attach (CIS resource conflict / IRQ steal in the probeβ†’attach window) β€” plausible on pccard, rare otherwise.
  • Not remotely triggerable, not an info leak, not memory corruption. Severity Low.

Why untested on this guest

  • if_sn.c is compiled only as the optional sn module (sys/conf/files:1247); its only front-end is pccard (sys/dev/netif/sn/if_sn_pccard.c:126-133, DEVMETHOD(device_attach, sn_pccard_attach) β†’ sn_attach).
  • The QEMU guest (see env.txt) exposes only vtnet0/lo0, has no PCMCIA slot and no SMC 91xx chip; therefore the attach path cannot execute. No amount of guest setup short of emulating PCMCIA + an SMC91C9x card can reach the bug β€” this is a genuine hardware gate, not a missing-setup case.

Fix validation

fix_status: not_testable for the same hardware reason. The one-line fix (check the return of sn_activate() in sn_attach and propagate the error) is contained in fix.diff; by inspection it makes the attach path return before any BASE-relative I/O and before the rman_get_cpuid call, mirroring the probe path at if_sn.c:1236-1237.

Kernel references

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

not_testable: fix validation requires SMC91xx PCMCIA hardware (guest has none). The proposed fix.diff makes sn_attach() bail out immediately on sn_activate() failure, mirroring sn_probe() at if_sn.c:1236-1237; by inspection this removes both the rman_get_cpuid(NULL) deref and all BASE=0 port I/O on the failing path.

findings/poc/DF-4354/fix.diff (1-hunk, error propagation); env.txt (hardware absent).
↓ fix.diffper-fix-DF-4354

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (root-cause chain with path:line), README.md (site table + fix), env.txt (guest lacks hardware: ifconfig -l shows vtnet0 lo0, no sn module loaded), fix.diff (one-line error propagation mirroring the probe path). Decisive lines: if_sn.c:164 (unchecked return), if_sn.c:216 (rman_get_cpuid(NULL)), sys/sys/rman.h:157 (((r)->r_rm->rm_cpuid)).

PoC changes

No executable PoC exists: path requires SMC91xx PCMCIA hardware absent from the guest. Evidence pack is source-level (VERDICT.md) plus guest hardware-inventory proof (env.txt).

Verified recommended fix

Check the return value of sn_activate() in sn_attach() and propagate the error before any register access or rman_get_cpuid call.

Verdict

sn_attach() (sys/dev/netif/sn/if_sn.c:164) discards the return value of sn_activate(); on any attach-time resource-allocation failure the driver proceeds with port_res=NULL, irq_res=NULL and BASE=0, writing the chip-id/MAC/CONFIG register writes into ISA DMA-controller ports 0x00-0x0F and then hitting ifq_set_cpuid(..., rman_get_cpuid(sc->irq_res)) at if_sn.c:216, a NULL double-deref (sys/sys/rman.h:157) that panics the kernel during device attach. Source-level certainty is high (the probe path checks the identical call at if_sn.c:1236-1237; the attach path does not), but the bug is hardware-gated: it requires an SMC91xx PCMCIA NIC, which the QEMU audit guest does not have (only vtnet0/lo0; if_sn is an optional module with a pccard-only front-end), so no runtime PoC is possible -> untested. Expected impact on real hardware is a boot/card-insert-time kernel panic plus stray low-port I/O; severity Low.