Thread (5 messages) flat view 5 messages, 1 author, 11d ago
DORMANTno replies

[PATCH wireless 4/4] wifi: cfg80211: get the wiphy out of a dying network namespace

From: Johannes Berg <johannes@sipsolutions.net>
Date: 2026-09-04 15:02:30
Subsystem: 802.11 (including cfg80211/nl80211), the rest · Maintainers: Johannes Berg, Linus Torvalds

From: Johannes Berg <redacted>

When a network namespace is destroyed, cfg80211_pernet_exit() moves any
wiphy back to the initial namespace, and just warns if that fails. But
moving an interface can fail (due to allocation failures), and then the
wiphy is left behind with a garbage netns pointer:

  Kernel mode fault at addr 0x30
  genlmsg_multicast_netns.constprop.0+0x46/0xcf [cfg80211]
  nl80211_notify_wiphy+0xcd/0xe8 [cfg80211]
  wiphy_unregister+0x169/0x3fc [cfg80211]

Note that commit debac3a20dec ("net: Remove conflicting altnames for
dying netns in __dev_change_net_namespace().") fixed another path
that could reach it without allocation failures.

Remove interfaces that cannot be moved instead of failing the switch,
so that the wiphy always ends up in the initial namespace. In this
case the netdev core will unregister the interfaces anyway.

Assisted-by: LLM
Reported-by: syzbot+c5f8a81e794d4a4f2014@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c5f8a81e794d4a4f2014
Fixes: 463d018323851 ("cfg80211: make aware of net namespaces")
Signed-off-by: Johannes Berg <redacted>
---
 net/wireless/core.c | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 9ee1c36f1262..25dd1a4d6b4e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -168,20 +168,24 @@ static int cfg80211_switch_wdev_netns(struct wireless_dev *wdev,
 	return err;
 }
 
-int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
-			  struct net *net)
+static int __cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
+				   struct net *net, bool force)
 {
 	struct net *old_net = wiphy_net(&rdev->wiphy);
-	struct wireless_dev *wdev;
+	struct wireless_dev *wdev, *tmp;
 	int err = 0;
 
-	if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
-		return -EOPNOTSUPP;
-
-	list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
+	list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) {
 		err = cfg80211_switch_wdev_netns(wdev, net);
-		if (err)
+		if (!err)
+			continue;
+		if (!force)
 			goto undo;
+		/* remove interfaces that fail to allow wiphy switching */
+		dev_close(wdev->netdev);
+		scoped_guard(wiphy, &rdev->wiphy)
+			cfg80211_unregister_wdev(wdev);
+		err = 0;
 	}
 
 	scoped_guard(wiphy, &rdev->wiphy) {
@@ -199,7 +203,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
 		/* this only fails on allocation failure */
 		err = device_rename(&rdev->wiphy.dev,
 				    dev_name(&rdev->wiphy.dev));
-		if (err)
+		if (err && !force)
 			wiphy_net_set(&rdev->wiphy, old_net);
 
 		nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
@@ -212,8 +216,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
 		}
 	}
 
-	if (!err)
-		return 0;
+	if (!err || force)
+		return err;
 
 	/* set to the last one to undo all of them */
 	wdev = list_entry(&rdev->wiphy.wdev_list, typeof(*wdev), list);
@@ -229,6 +233,15 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
 	return err;
 }
 
+int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
+			  struct net *net)
+{
+	if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
+		return -EOPNOTSUPP;
+
+	return __cfg80211_switch_netns(rdev, net, false);
+}
+
 static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
 {
 	struct cfg80211_registered_device *rdev = data;
@@ -1882,7 +1895,7 @@ static void __net_exit cfg80211_pernet_exit(struct net *net)
 	rtnl_lock();
 	for_each_rdev(rdev) {
 		if (net_eq(wiphy_net(&rdev->wiphy), net))
-			WARN_ON(cfg80211_switch_netns(rdev, &init_net));
+			WARN_ON(__cfg80211_switch_netns(rdev, &init_net, true));
 	}
 	rtnl_unlock();
 }
-- 
2.55.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help