Commit 38ec7c6b authored by Johannes Berg's avatar Johannes Berg
Browse files

virt_wifi: fix deadlock on RTNL



Fix a regression where everything in virt_wifi would just hang. This
happened due to overlapping changes between commit a05829a7
("cfg80211: avoid holding the RTNL when calling the driver") which
had originally needed to change the locking, but then I introduced
commit 2fe8ef10 ("cfg80211: change netdev registration/unregistration
semantics") instead. virt_wifi somehow fell through the cracks when
I undid all the previous locking changes. Fix it now.

Fixes: a05829a7 ("cfg80211: avoid holding the RTNL when calling the driver")
Reported-by: default avatar <syzbot+3d2d5e6cc3fb15c6a0fd@syzkaller.appspotmail.com>
Link: https://lore.kernel.org/r/20210127215941.2d6a97b09784.I4f1fac32f67045171be50931f44d77e150911bee@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent a05829a7
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -537,9 +537,7 @@ static int virt_wifi_newlink(struct net *src_net, struct net_device *dev,
	dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
	dev->ieee80211_ptr->wiphy = common_wiphy;

	wiphy_lock(common_wiphy);
	err = register_netdevice(dev);
	wiphy_unlock(common_wiphy);
	if (err) {
		dev_err(&priv->lowerdev->dev, "can't register_netdevice: %d\n",
			err);
@@ -562,9 +560,7 @@ static int virt_wifi_newlink(struct net *src_net, struct net_device *dev,

	return 0;
unregister_netdev:
	wiphy_lock(common_wiphy);
	unregister_netdevice(dev);
	wiphy_unlock(common_wiphy);
free_wireless_dev:
	kfree(dev->ieee80211_ptr);
	dev->ieee80211_ptr = NULL;
@@ -590,9 +586,7 @@ static void virt_wifi_dellink(struct net_device *dev,
	netdev_rx_handler_unregister(priv->lowerdev);
	netdev_upper_dev_unlink(priv->lowerdev, dev);

	wiphy_lock(common_wiphy);
	unregister_netdevice_queue(dev, head);
	wiphy_unlock(common_wiphy);
	module_put(THIS_MODULE);

	/* Deleting the wiphy is handled in the module destructor. */
@@ -631,9 +625,7 @@ static int virt_wifi_event(struct notifier_block *this, unsigned long event,
		upper_dev = priv->upperdev;

		upper_dev->rtnl_link_ops->dellink(upper_dev, &list_kill);
		wiphy_lock(common_wiphy);
		unregister_netdevice_many(&list_kill);
		wiphy_unlock(common_wiphy);
		break;
	}