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

sc_curmac left NULL after failed band-switch/hw-reset while RUNNING: bwn_stop/bwn_detach/bwn_suspend NULL-deref panic

Summary

bwn_switch_band and bwn_hwreset set sc->sc_curmac=NULL when re-init fails, without clearing BWN_FLAG_RUNNING; callers of bwn_set_channel ignore the error. The next bwn_stop - from bwn_parent, bwn_suspend or bwn_detach - dereferences the NULL mac and panics. The TX path guards mac==NULL but stop/detach/suspend do not. Error-path reachable on any BCM43xx system (firmware re-load failure during channel change or device reset - e.g. firmware files removed after first bring-up, flaky or malicious card); not user-triggerable by RF alone. Source-certain; guest hardware-absent.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3595 Β· 7 files
FileTypeDescriptionSize
README.md β€” 762 B ↓ raw
VERDICT.md β€” 2.9 KB ↓ raw
probe.sh β€” 838 B view raw
run.log β€” 581 B view raw
fix.diff β€” 541 B view raw
manifest.json β€” 998 B view raw
verdict.json β€” 2.0 KB view raw

DF-3595 β€” sc_curmac left NULL after failed band-switch/hw-reset while RUNNING: bwn_stop/bwn_detach/bwn_suspend NULL-deref panic

Build / Run / Expected

# on the DF guest, as root:
sh probe.sh

Guest result: driver resident, no Broadcom hardware β†’ runtime inconclusive. On a BCM43xx machine: bring the interface up (firmware loads OK, RUNNING set), then force bwn_switch_band()/bwn_hwreset() to fail β€” e.g. make bwn_core_init() fail on re-init (unload the bwn v4 firmware files after first bring-up, or flaky/malicious card) β€” then ifconfig bwn0 down, devdetach, or suspend: bwn_stop() dereferences sc->sc_curmac == NULL at if_bwn.c:2048 β†’ immediate kernel NULL-deref panic (mac->mac_status read at address ~0x18).

VERDICT.md
↓ download raw

VERDICT β€” DF-3595

Status: inconclusive at runtime (no bwn hardware on the audit guest); defect source-certain. Impact: kernel NULL-deref panic (local DoS) via error-path lifetime bug.

Root cause (path:line)

Two failure paths clear sc->sc_curmac to NULL without clearing BWN_FLAG_RUNNING or otherwise quiescing the softc:

  1. bwn_switch_band() β€” on bwn_core_init(up_dev) failure: fail: sc->sc_curmac = NULL; return (err); (sys/dev/netif/bwn/bwn/if_bwn.c:4763-4765).
  2. bwn_hwreset() β€” on bwn_core_init(mac) failure: sc->sc_curmac = NULL; (if_bwn.c:5363-5366).

In both cases the interface was previously up (bwn_init() set BWN_FLAG_RUNNING at :2032; callers of bwn_set_channel ignore the band-switch error β€” :1906-1908 only jumps to the radiotap tail β€” and bwn_restart schedules hwreset from interrupt context at :5064).

Every subsequent state-changing entry point that trusts sc_curmac then dereferences NULL:

  • bwn_stop(): struct bwn_mac *mac = sc->sc_curmac; (:2042) … if (mac->mac_status >= BWN_MAC_STATUS_INITED) (:2048) β€” NULL deref. Reached from bwn_parent() (:910), bwn_suspend() (:7374), and bwn_detach() (:791-794 β€” note bwn_detach also fetches mac at :783 and calls bwn_dma_free(mac) at :795 unconditionally for attached devices).
  • Contrast: bwn_start() does check (mac == NULL || at :949), and bwn_update_promisc/bwn_wme_update re-fetch with NULL guards (:1827-1828, :1850-1851) β€” the author knew sc_curmac can be NULL and guarded the TX/promisc paths but not stop/detach/suspend.

Reachability of the failure itself: bwn_core_init fails whenever firmware re-load fails (bwn_fw_fillinfo β†’ bwn_fw_get β†’ firmware_get ENOENT, if_bwn.c:2298), PMU/powerup issues, or PHY re-init errors β€” a realistic field state on systems whose firmware files disappear after first load, or on a malicious card that fails the second init deliberately. The error paths at :4764/:5365 then arm the panic for the next ifconfig down/detach.

Why runtime reproduction was not possible

Same as DF-3593/3594: no Broadcom card on the guest (run.log). The attach→init→band-switch-fail→stop sequence cannot be entered.

Fix

Treat curmac==NULL as already-down in bwn_stop() (and guard bwn_detach's bwn_dma_free), or clear BWN_FLAG_RUNNING when nulled β€” see fix.diff.

Artifacts

  • probe.sh, run.log β€” guest probe (driver residency + hardware absence)
  • fix.diff β€” proposed patch vs read-only sys/ tree (never applied)

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 authored against read-only sys/; cannot baseline-validate without BCM43xx hardware

fix.diff in this pack
↓ fix.diffper-fix-DF-3595

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md path:line trace; run.log guest probe; fix.diff adds NULL guard clearing RUNNING in bwn_stop

PoC changes

No runnable PoC possible without hardware; probe.sh substitutes

Verified recommended fix

NULL-guard sc_curmac in bwn_stop (clear BWN_FLAG_RUNNING and return)

Verdict

Source-certain error-path lifetime bug: bwn_switch_band (if_bwn.c:4764) and bwn_hwreset (if_bwn.c:5365) set sc->sc_curmac=NULL on re-init failure while BWN_FLAG_RUNNING stays set and callers ignore the error; the next bwn_stop (if_bwn.c:2048 — from bwn_parent :910, bwn_suspend :7374, bwn_detach :791-794) dereferences the NULL mac and panics. Driver already guards mac==NULL on the TX path (if_bwn.c:949) but not on stop/detach/suspend. Guest has no Broadcom device (run.log) so the up→band-switch-fail→down sequence cannot run; trigger requires fw re-load failure (missing firmware after first load, flaky or malicious card).