[PATCH 6.1] Revert "wifi: mac80211: fix RCU list iterations"

Fedor Pchelkin posted 1 patch 2 weeks ago
net/mac80211/chan.c | 4 +---
net/mac80211/mlme.c | 2 +-
net/mac80211/scan.c | 2 +-
net/mac80211/util.c | 4 +---
4 files changed, 4 insertions(+), 8 deletions(-)
[PATCH 6.1] Revert "wifi: mac80211: fix RCU list iterations"
Posted by Fedor Pchelkin 2 weeks ago
This reverts commit b0b2dc1eaa7ec509e07a78c9974097168ae565b7 which is
commit ac35180032fbc5d80b29af00ba4881815ceefcb6 upstream.

The reverted commit is based heavily on wiphy locking changes made by the
"wifi: cfg80211/mac80211: locking cleanups" series [1] introduced since
6.7 kernel and not supposed to be backported to old stable branches.

It breaks locking rules in the context of old stables leading e.g. to the
following lockdep splat there - ieee80211_get_max_required_bw() is
actually called under RCU reader lock in 6.1/6.6, not the wiphy mutex.

WARNING: CPU: 3 PID: 8711 at net/mac80211/chan.c:248 ieee80211_get_max_required_bw+0x423/0x4e0 net/mac80211/chan.c:248
Modules linked in:
CPU: 3 PID: 8711 Comm: kworker/u8:6 Not tainted 6.1.113-syzkaller-00105-g9859ec205cfa #0
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
Workqueue: phy155 ieee80211_iface_work
RIP: 0010:ieee80211_get_max_required_bw+0x423/0x4e0 net/mac80211/chan.c:248
Call Trace:
 <TASK>
 ieee80211_get_chanctx_vif_max_required_bw net/mac80211/chan.c:294 [inline]
 ieee80211_get_chanctx_max_required_bw net/mac80211/chan.c:336 [inline]
 _ieee80211_recalc_chanctx_min_def+0x5e6/0xf30 net/mac80211/chan.c:381
 ieee80211_recalc_chanctx_min_def+0x21/0x80 net/mac80211/chan.c:462
 ieee80211_recalc_min_chandef+0x17a/0x590 net/mac80211/util.c:2908
 sta_info_move_state+0x748/0x8c0 net/mac80211/sta_info.c:2301
 ieee80211_assoc_success net/mac80211/mlme.c:5001 [inline]
 ieee80211_rx_mgmt_assoc_resp.cold+0x1335/0x69ec net/mac80211/mlme.c:5201
 ieee80211_sta_rx_queued_mgmt+0x40f/0x2270 net/mac80211/mlme.c:5831
 ieee80211_iface_process_skb net/mac80211/iface.c:1665 [inline]
 ieee80211_iface_work+0xa31/0xd30 net/mac80211/iface.c:1722
 process_one_work+0xa72/0x1590 kernel/workqueue.c:2292
 worker_thread+0x632/0x1240 kernel/workqueue.c:2439
 kthread+0x2e1/0x3a0 kernel/kthread.c:376
 ret_from_fork+0x22/0x30 arch/x86/entry/entry_64.S:295

[1]: https://lore.kernel.org/linux-wireless/20230828115927.116700-41-johannes@sipsolutions.net/

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
---
 net/mac80211/chan.c | 4 +---
 net/mac80211/mlme.c | 2 +-
 net/mac80211/scan.c | 2 +-
 net/mac80211/util.c | 4 +---
 4 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 807bea1a7d3c..f07e34bed8f3 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -245,9 +245,7 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata,
 	enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
 	struct sta_info *sta;
 
-	lockdep_assert_wiphy(sdata->local->hw.wiphy);
-
-	list_for_each_entry(sta, &sdata->local->sta_list, list) {
+	list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
 		if (sdata != sta->sdata &&
 		    !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
 			continue;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ee9ec74b9553..9a5530ca2f6b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -660,7 +660,7 @@ static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
 		bool disable_mu_mimo = false;
 		struct ieee80211_sub_if_data *other;
 
-		list_for_each_entry(other, &local->interfaces, list) {
+		list_for_each_entry_rcu(other, &local->interfaces, list) {
 			if (other->vif.bss_conf.mu_mimo_owner) {
 				disable_mu_mimo = true;
 				break;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index edbf468e0bea..f1147d156c1f 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -501,7 +501,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 	 * the scan was in progress; if there was none this will
 	 * just be a no-op for the particular interface.
 	 */
-	list_for_each_entry(sdata, &local->interfaces, list) {
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		if (ieee80211_sdata_running(sdata))
 			ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 	}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3fe15089b24f..738f1f139a90 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -767,9 +767,7 @@ static void __iterate_interfaces(struct ieee80211_local *local,
 	struct ieee80211_sub_if_data *sdata;
 	bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
 
-	list_for_each_entry_rcu(sdata, &local->interfaces, list,
-				lockdep_is_held(&local->iflist_mtx) ||
-				lockdep_is_held(&local->hw.wiphy->mtx)) {
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		switch (sdata->vif.type) {
 		case NL80211_IFTYPE_MONITOR:
 			if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
-- 
2.39.5