[PATCH RFC] net: handle device_rename() failures during netns switch

"syzbot" <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
Memory allocation failures during a network namespace switch (e.g., in
device_rename()) trigger WARN_ON(err) in __dev_change_net_namespace(),
cfg802154_switch_netns(), and cfg80211_switch_netns(). WARN_ON must not be
used for conditions that can legitimately happen, such as -ENOMEM, because
it crashes machines with panic_on_warn enabled. A less severe logging
mechanism like dev_warn() or netdev_warn() should be used instead.

Handling these failures is tricky. Reverting the logical namespace change
(dev_net_set(dev, net_old)) when device_rename() fails introduces a KASAN
slab-use-after-free bug. This happens because cfg802154_pernet_exit() and
cfg80211_pernet_exit() attempt to move devices back to init_net when a
namespace is destroyed. If device_rename() fails and the change is
reverted, devices are left in the dying namespace. When the namespace is
subsequently destroyed, default_device_exit_batch() unregisters all
remaining netdevs. Drivers like mac802154 and mac80211 do not properly
handle NETDEV_UNREGISTER for their internal interface lists, leading to a
UAF when the list is later accessed.

On the other hand, simply ignoring the failure and accepting the sysfs
inconsistency leads to another UAF in kernfs_ns_id. device_rename() is
responsible for updating the sysfs directory's namespace tag (kn->ns). If
it fails, the sysfs directory remains tagged with the old network
namespace. When the old namespace is destroyed, the kn->ns pointer becomes
dangling. Later, when the device is unregistered, device_del() tries to
remove sysfs entries and dereferences this freed namespace pointer.

To safely handle device_rename() failures without causing either UAF, we
must not revert the logical namespace change. This ensures the device
successfully moves to the new namespace (e.g., init_net) and avoids being
unregistered by the dying namespace's cleanup routine. Instead, we manually
update the sysfs namespace tag. If device_rename() fails, the kobject still
retains its old name. We can call sysfs_rename_dir_ns() with the old name
and the new namespace. Because the name hasn't changed, kernfs_rename_ns()
will not allocate memory and will successfully update the namespace tag,
preventing the kernfs UAF. Finally, we replace the WARN_ON(err) calls with
netdev_warn() and dev_warn() across net/core/dev.c, net/ieee802154/core.c,
and net/wireless/core.c to log the expected memory allocation failures
without crashing the system.

Fixes: 8b41d1887db7 ("[NET]: Fix running without sysfs")
Assisted-by: Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=3344d668bbbc12996d46
Link: https://syzkaller.appspot.com/ai_job?id=85f31f19-953c-4b06-8f37-956317d66ff1
To: "Alexander Aring" <[email protected]>
To: "David S. Miller" <[email protected]>
To: "Eric Dumazet" <[email protected]>
To: "Johannes Berg" <[email protected]>
To: "Jakub Kicinski" <[email protected]>
To: <[email protected]>
To: <[email protected]>
To: "Miquel Raynal" <[email protected]>
To: <[email protected]>
To: "Paolo Abeni" <[email protected]>
To: "Stefan Schmidt" <[email protected]>
Cc: "Simon Horman" <[email protected]>
Cc: <[email protected]>
Cc: "Stanislav Fomichev" <[email protected]>

---
diff --git a/net/core/dev.c b/net/core/dev.c
index 0c6c270d9..25f0d8bf5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -12652,7 +12652,12 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
 	dev_set_uevent_suppress(&dev->dev, 1);
 	err = device_rename(&dev->dev, dev->name);
 	dev_set_uevent_suppress(&dev->dev, 0);
-	WARN_ON(err);
+	if (err) {
+		netdev_warn(dev, "failed to rename device: %d\n", err);
+		sysfs_rename_dir_ns(&dev->dev.kobj,
+				    kobject_name(&dev->dev.kobj),
+				    kobject_namespace(&dev->dev.kobj));
+	}
 
 	/* Send a netdev-add uevent to the new namespace */
 	kobject_uevent(&dev->dev.kobj, KOBJ_ADD);
@@ -12662,7 +12667,8 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
 	 * namespace is different from the original one.
 	 */
 	err = netdev_change_owner(dev, net_old, net);
-	WARN_ON(err);
+	if (err)
+		netdev_warn(dev, "failed to change owner: %d\n", err);
 
 	netdev_lock(dev);
 	dev->moving_ns = false;
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index 89b671b12..ddff07ae8 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -245,7 +245,11 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
 			wpan_dev->netdev->netns_immutable = false;
 			err = dev_change_net_namespace(wpan_dev->netdev, net,
 						       "wpan%d");
-			WARN_ON(err);
+			if (err)
+				dev_warn(
+					&rdev->wpan_phy.dev,
+					"failed to revert netns change for wpan_dev: %d\n",
+					err);
 			wpan_dev->netdev->netns_immutable = true;
 		}
 
@@ -255,7 +259,9 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
 	wpan_phy_net_set(&rdev->wpan_phy, net);
 
 	err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev));
-	WARN_ON(err);
+	if (err)
+		dev_warn(&rdev->wpan_phy.dev, "failed to rename device: %d\n",
+			 err);
 
 	return 0;
 }
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6783e0672..824009c30 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -184,7 +184,11 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
 			wdev->netdev->netns_immutable = false;
 			err = dev_change_net_namespace(wdev->netdev, net,
 							"wlan%d");
-			WARN_ON(err);
+			if (err)
+				dev_warn(
+					&rdev->wiphy.dev,
+					"failed to revert netns change for wdev: %d\n",
+					err);
 			wdev->netdev->netns_immutable = true;
 		}
 
@@ -204,7 +208,9 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
 	wiphy_net_set(&rdev->wiphy, net);
 
 	err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev));
-	WARN_ON(err);
+	if (err)
+		dev_warn(&rdev->wiphy.dev, "failed to rename device: %d\n",
+			 err);
 
 	nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
 


base-commit: e7ae89a0c97ce2b68b0983cd01eda67cf373517d
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.