⬢ DragonFlyBSD Kernel Audit
DF-3969 / trigger.c
← back to finding ↓ download raw
/*
 * 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;
}