DF-3969 / trigger.c
/* * DF-3969 trigger sketch — rt2560_scan_end NULL-vap deref race (DF-3968 family) * ============================================================================ * rt2560.c:2566-2574: * rt2560_scan_end(struct ieee80211com *ic) * { * struct rt2560_softc *sc = ic->ic_softc; * struct ieee80211vap *vap = ic->ic_scan->ss_vap; // cleared by vdetch * * rt2560_enable_tsf_sync(sc); * rt2560_set_bssid(sc, vap->iv_bss->ni_bssid); // NULL deref * * rt2560.c:2274-2284 (rt2560_enable_tsf_sync): * struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); // may be NULL * ... * tmp = 16 * vap->iv_bss->ni_intval; // NULL deref * * The call site races last-vap destruction exactly as in DF-3968: * sys/netproto/802_11/wlan/ieee80211_scan_sw.c:781-798 (scan_end): * IEEE80211_UNLOCK(ic); * ic->ic_scan_end(ic); <-- driver called UNLOCKED * IEEE80211_LOCK(ic); * /* XXX scan state can change! Re-validate scan state! * / * while ieee80211_vap_delete -> ieee80211_scan_vdetach * (ieee80211_scan.c:147-155) sets ss->ss_vap = NULL and removes the vap * from ic_vaps under the COM lock. If the only vap is destroyed inside * the unlocked window: * - scan_end: ss_vap == NULL -> vap->iv_bss reads NULL+offset, and * - enable_tsf_sync: TAILQ_FIRST(&ic->ic_vaps) == NULL -> NULL deref * => Fatal trap 12. * * The rt2560-specific twist vs rt2661: scan_end derefs ss_vap (cleared by * vdetch) AND enable_tsf_sync derefs TAILQ_FIRST (empty list); either one * faults first depending on which field the race leaves stale. * * On-hardware trigger (needs an RT2560 PCI NIC; this audit guest has none): * # while true; do * # ifconfig wlan0 create wlandev ral0 wlanmode sta * # (associate; background scan running) * # ifconfig wlan0 destroy & # race last-vap delete vs scan end * # done * Window = the unlocked ic_scan_end driver call; repeat until hit. */ #include <stdio.h> int main(void) { printf("hardware-gated: see header comment for the on-target recipe\n"); return 0; } |