⬢ DragonFlyBSD Kernel Audit
DF-3470 / analysis.txt
← back to finding ↓ download raw
# DF-3470 — code-level evidence (guest + tree)

## Guard exists but is never armed: `nrefs` occurrence counts

$ grep -rn "nrefs" sys/netproto/802_11/ | grep -v "^Binary"
sys/netproto/802_11/wlan_wep/ieee80211_crypto_wep.c:86:static	int nrefs = 0;
sys/netproto/802_11/wlan_wep/ieee80211_crypto_wep.c:108:	nrefs++;			/* NB: we assume caller locking */
sys/netproto/802_11/wlan_wep/ieee80211_crypto_wep.c:118:	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
sys/netproto/802_11/wlan_wep/ieee80211_crypto_wep.c:119:	nrefs--;			/* NB: we assume caller locking */
sys/netproto/802_11/wlan/ieee80211_ratectl_none.c:96:static	int nrefs = 0;      <-- never used again
sys/netproto/802_11/wlan/ieee80211_rssadapt.c:97:static	int nrefs = 0;         <-- never used again
sys/netproto/802_11/wlan/ieee80211_scan_sta.c:150:static	int nrefs = 0;
sys/netproto/802_11/wlan/ieee80211_scan_sta.c:178:	nrefs++;			/* NB: we assume caller locking */
sys/netproto/802_11/wlan/ieee80211_scan_sta.c:195:		KASSERT(nrefs > 0, ("imbalanced attach/detach"));
sys/netproto/802_11/wlan/ieee80211_scan_sta.c:196:		nrefs--;			/* NB: we assume caller locking */
sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c:107:static	int nrefs = 0;    (+108/137/138 ++/--)
sys/netproto/802_11/wlan/ieee80211_amrr.c:77:static	int nrefs = 0;            <-- never used again (default algorithm!)

## The unload guard that is bypassed (sys/netproto/802_11/ieee80211_dragonfly.h)

#define	_IEEE80211_POLICY_MODULE(policy, name, version)			\
...
	case MOD_UNLOAD:						\
		error = 0;						\
		if (nrefs) {						\
			kprintf("wlan_" #name ": still in use (%u "	\
				"dynamic refs)\n",			\
				nrefs);					\
			error = EBUSY;					\
		} else if (type == MOD_UNLOAD) {			\
			SET_FOREACH(iter, policy##_set) {		\
				f = (void*) *iter;			\
				f(type);				\
			}						\
		}							\
...
IEE80211_RATECTL_ALG(name, alg, v) -> MOD_UNLOAD -> ieee80211_ratectl_unregister(alg)
                                     (ratectl.c:66-71: ratectls[type] = NULL, no user check)

## The dangling consumer chain

ratectl.c:152   vap->iv_rate = ratectls[type];        /* pointer INTO the module */
ratectl.c:123   vap->iv_rate->ir_init(vap);
ratectl.h:88    vap->iv_rate->ir_rate(ni, arg, iarg);             /* every TX */
ratectl.c:83    ieee80211_ratectl_node_stats(ni, sb) ->
ratectl.h:121   vap->iv_rate->ir_node_stats(ni, s)   /* world-readable rate_stats sysctl
                                                         (ratectl.c:127-129, CTLFLAG_RD) */
ratectl.h:70    vap->iv_rate->ir_deinit(vap);                     /* vap teardown */

## Guest facts (stock INVARIANTS kernel #0)

$ kldstat -v | grep -wE "wlan_amrr|wlan_rssadapt"
		180 wlan_amrr                     <- compiled INTO the kernel image
$ kldunload wlan_amrr
kldunload: can't find file wlan_amrr: No such file or directory
$ grep -c nrefs /usr/src/sys/netproto/802_11/wlan/ieee80211_amrr.c
1
=> On this guest the unload cannot be attempted at all (algorithm built-in),
   and no 802.11 hardware exists to attach a vap. Runtime reproduction of the
   dangling iv_rate call is therefore impossible here; the defect is proven
   from source (missing nrefs increment in amrr/rssadapt/none + no registry
   backstop).