summaryrefslogtreecommitdiff
path: root/net/wireless/core.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2021-02-01 19:20:50 +0100
committerJohannes Berg <johannes.berg@intel.com>2021-02-01 19:30:54 +0100
commit40c575d1ec71f7a61c73ba1603a69650c130559c (patch)
treefd01bc1a23dd89442544f2e9e56dd13269cdb00f /net/wireless/core.c
parent776a39b8196dbca4afb69669db0d9926ffac29ab (diff)
cfg80211: fix netdev registration deadlock
If register_netdevice() fails after having called cfg80211's netdev notifier (cfg80211_netdev_notifier_call) it will call the notifier again with UNREGISTER. This would then lock the wiphy mutex because we're marked as registered, which causes a deadlock. Fix this by separately keeping track of whether or not we're in the middle of registering to also skip the notifier call on this unregister. Reported-by: syzbot+2ae0ca9d7737ad1a62b7@syzkaller.appspotmail.com Fixes: a05829a7222e ("cfg80211: avoid holding the RTNL when calling the driver") Link: https://lore.kernel.org/r/20210201192048.ed8bad436737.I7cae042c44b15f80919a285799a15df467e9d42d@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 18f9a5c214b5..a2785379df6e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1346,6 +1346,7 @@ int cfg80211_register_netdevice(struct net_device *dev)
/* we'll take care of this */
wdev->registered = true;
+ wdev->registering = true;
ret = register_netdevice(dev);
if (ret)
goto out;
@@ -1361,6 +1362,7 @@ int cfg80211_register_netdevice(struct net_device *dev)
cfg80211_register_wdev(rdev, wdev);
ret = 0;
out:
+ wdev->registering = false;
if (ret)
wdev->registered = false;
return ret;
@@ -1403,7 +1405,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
* It is possible to get NETDEV_UNREGISTER multiple times,
* so check wdev->registered.
*/
- if (wdev->registered) {
+ if (wdev->registered && !wdev->registering) {
wiphy_lock(&rdev->wiphy);
_cfg80211_unregister_wdev(wdev, false);
wiphy_unlock(&rdev->wiphy);