DF-3430 / trigger_create_wds_refleak.c
/* DF-3430 — ieee80211_create_wds(): the "station already in use" branch * leaks the node reference taken by ieee80211_find_node_locked(). * * sys/netproto/802_11/wlan/ieee80211_wds.c:149-188 * * IEEE80211_NODE_LOCK(nt); * ni = ieee80211_find_node_locked(&ic->ic_sta, vap->iv_des_bssid); * // ^ takes +1 reference (ieee80211_node.c:1391: * // ieee80211_ref_node(ni) "mark referenced") * if (ni == NULL) { * ... /* nothing to free - ok */ * } else if (ni->ni_wdsvap != NULL) { * ...DPRINTF... /* LEAK: ni's reference never dropped */ * } else { * obss = vap->iv_bss; /* success: find-ref transferred to iv_bss */ * vap->iv_bss = ni; * ni->ni_wdsvap = vap; * } * IEEE80211_NODE_UNLOCK(nt); * if (obss != NULL) * ieee80211_free_node(obss); * * In the middle branch the +1 reference from find_node_locked is never * released: the station node's refcount is permanently inflated. The node * can then never be reclaimed (node_reclaim drops to 1, never 0), polluting * the station table forever. * * Trigger: two WDS vaps whose iv_des_bssid is the same associated station * (e.g. management daemon plumbs a second DWDS vap for an already-hooked * station, or races two INIT->RUN transitions of different vaps): every * RUN transition of the losing vap leaks one reference. RUN->INIT of the * winning vap clears ni_wdsvap (ieee80211_node.c:2004-2010 second pass), * so alternating up/down cycles of the two vaps leak unboundedly. * * Upstream: FreeBSD's ieee80211_create_wds has the identical branch * (sys/net80211/ieee80211_wds.c:161-167 as of HEAD) - inherited defect. * * Low severity: requires privileged local plumbing (root creates vaps); * impact is node-table pollution / slow resource exhaustion, not memory * unsafety. Phase V skipped per audit policy for Low findings; analysis * pack only. */ int main(void) { return 1; } |