Skip to content

Commit 40c575d

Browse files
committed
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: [email protected] Fixes: a05829a ("cfg80211: avoid holding the RTNL when calling the driver") Link: https://lore.kernel.org/r/20210201192048.ed8bad436737.I7cae042c44b15f80919a285799a15df467e9d42d@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 776a39b commit 40c575d

File tree

2 files changed

+6
-2
lines changed

2 files changed

+6
-2
lines changed

include/net/cfg80211.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5299,6 +5299,8 @@ static inline void wiphy_unlock(struct wiphy *wiphy)
52995299
* @wiphy: pointer to hardware description
53005300
* @iftype: interface type
53015301
* @registered: is this wdev already registered with cfg80211
5302+
* @registering: indicates we're doing registration under wiphy lock
5303+
* for the notifier
53025304
* @list: (private) Used to collect the interfaces
53035305
* @netdev: (private) Used to reference back to the netdev, may be %NULL
53045306
* @identifier: (private) Identifier used in nl80211 to identify this
@@ -5382,7 +5384,7 @@ struct wireless_dev {
53825384

53835385
struct mutex mtx;
53845386

5385-
bool use_4addr, is_running, registered;
5387+
bool use_4addr, is_running, registered, registering;
53865388

53875389
u8 address[ETH_ALEN] __aligned(sizeof(u16));
53885390

net/wireless/core.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,7 @@ int cfg80211_register_netdevice(struct net_device *dev)
13461346

13471347
/* we'll take care of this */
13481348
wdev->registered = true;
1349+
wdev->registering = true;
13491350
ret = register_netdevice(dev);
13501351
if (ret)
13511352
goto out;
@@ -1361,6 +1362,7 @@ int cfg80211_register_netdevice(struct net_device *dev)
13611362
cfg80211_register_wdev(rdev, wdev);
13621363
ret = 0;
13631364
out:
1365+
wdev->registering = false;
13641366
if (ret)
13651367
wdev->registered = false;
13661368
return ret;
@@ -1403,7 +1405,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
14031405
* It is possible to get NETDEV_UNREGISTER multiple times,
14041406
* so check wdev->registered.
14051407
*/
1406-
if (wdev->registered) {
1408+
if (wdev->registered && !wdev->registering) {
14071409
wiphy_lock(&rdev->wiphy);
14081410
_cfg80211_unregister_wdev(wdev, false);
14091411
wiphy_unlock(&rdev->wiphy);

0 commit comments

Comments
 (0)