This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / machines / ignavia / mt76-wcid-poll-race.patch
4.3 kB 97 lines
1wifi: mt76: fix wcid poll list corruption on station removal 2 3Three system freezes on 2026-07-03 (ignavia, Framework 13 AMD, MT7925), 4two with captured oopses, both identical, on kernels 7.0.11 and 7.1.2: 5 6 wlp192s0: send auth to 80:2a:a8:52:b0:2f (try 1/3) 7 slab kmalloc-rnd-11-8k start ... pointer offset 4160 size 8192 8 list_add corruption. prev->next should be next (X), but was Y. (prev=Y) 9 kernel BUG at lib/list_debug.c:32! 10 11prev == prev->next means the tail node of sta_poll_list was 12re-initialized (INIT_LIST_HEAD) while still linked. The 8k slab is the 13ieee80211_sta + drv_priv allocation holding the embedded mt76_wcid. 14 15Race (mt7925, frequent roaming between APs of the same ESS): 16 17 CPU0 (rx/txs softirq) CPU1 (mac80211 sta teardown) 18 wcid = rcu_dereference(...) 19 rcu_assign_pointer(wcid[idx], NULL) 20 mt76_wcid_cleanup() 21 list_del_init(&wcid->poll_list) 22 mt76_wcid_add_poll(wcid) 23 wcid->sta still 1 -> re-adds 24 dying wcid to sta_poll_list 25 sta freed after RCU grace period 26 ... sta_poll_list tail dangles into freed slab ... 27 roam re-add reuses slab slot: 28 mt76_wcid_init() 29 INIT_LIST_HEAD(&wcid->poll_list) 30 -> still-linked tail self-loops 31 next mt76_wcid_add_poll() 32 list_add_tail() -> BUG 33 34mt76_reset_device() and the mt7915/mt7996 remove paths already clear 35wcid->sta (and set sta_disabled) at teardown; the mt792x remove paths 36never do, so the !wcid->sta guard in mt76_wcid_add_poll() is 37ineffective there, and it runs before taking sta_poll_lock anyway. 38 39Fix: 40 - mt76_wcid_cleanup(): mark the wcid dead (sta = 0, sta_disabled = 1) 41 under sta_poll_lock, in the same critical section that unlinks 42 poll_list. 43 - mt76_wcid_add_poll(): re-check wcid->sta under sta_poll_lock so the 44 check cannot race with cleanup. 45 - mt7925_mac_sta_poll(): take list_first_entry under sta_poll_lock 46 (same discipline mt7921 uses); the unlocked read can race with 47 cleanup unlinking the entry from the spliced private list. 48 49diff -ruN a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c 50--- a/drivers/net/wireless/mediatek/mt76/mac80211.c 2026-06-27 12:08:18.000000000 +0200 51+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c 2026-07-03 16:04:01.869430650 +0200 52@@ -1727,6 +1727,13 @@ 53 * when mt76_wcid_add_poll() checks list_empty(). 54 */ 55 spin_lock_bh(&dev->sta_poll_lock); 56+ /* Mark the wcid dead in the same critical section, so a concurrent 57+ * mt76_wcid_add_poll() from the rx/txs path cannot re-add it after 58+ * we unlink it. Freed wcids left on sta_poll_list corrupt the list 59+ * once the slab slot is reused and re-initialized. 60+ */ 61+ wcid->sta = 0; 62+ wcid->sta_disabled = 1; 63 if (!list_empty(&wcid->poll_list)) 64 list_del_init(&wcid->poll_list); 65 spin_unlock_bh(&dev->sta_poll_lock); 66@@ -1759,7 +1766,10 @@ 67 return; 68 69 spin_lock_bh(&dev->sta_poll_lock); 70- if (list_empty(&wcid->poll_list)) 71+ /* Re-check under the lock: mt76_wcid_cleanup() clears wcid->sta in 72+ * its sta_poll_lock section, so this cannot race with teardown. 73+ */ 74+ if (wcid->sta && list_empty(&wcid->poll_list)) 75 list_add_tail(&wcid->poll_list, &dev->sta_poll_list); 76 spin_unlock_bh(&dev->sta_poll_lock); 77 } 78diff -ruN a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c 79--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c 2026-06-27 12:08:18.000000000 +0200 80+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c 2026-07-03 16:04:01.869762977 +0200 81@@ -46,12 +46,14 @@ 82 u16 idx; 83 u8 bw; 84 85- if (list_empty(&sta_poll_list)) 86+ spin_lock_bh(&dev->mt76.sta_poll_lock); 87+ if (list_empty(&sta_poll_list)) { 88+ spin_unlock_bh(&dev->mt76.sta_poll_lock); 89 break; 90+ } 91 mlink = list_first_entry(&sta_poll_list, 92 struct mt792x_link_sta, wcid.poll_list); 93 msta = mlink->sta; 94- spin_lock_bh(&dev->mt76.sta_poll_lock); 95 list_del_init(&mlink->wcid.poll_list); 96 spin_unlock_bh(&dev->mt76.sta_poll_lock); 97