From: Johannes Berg <johannes.berg@xxxxxxxxx> 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@xxxxxxxxxxxxxxxxxxxxxxxxx Fixes: a05829a7222e ("cfg80211: avoid holding the RTNL when calling the driver") Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx> --- include/net/cfg80211.h | 3 +++ net/wireless/core.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4741d71ead21..ceeeb1d7cfe5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4788,6 +4788,8 @@ struct wiphy_iftype_akm_suites { * the same number of arbitrary MAC addresses. * @registered: protects ->resume and ->suspend sysfs callbacks against * unregister hardware + * @registering: indicates we're doing registration under wiphy lock + * for the notifier * @debugfsdir: debugfs directory used for this wiphy (ieee80211/<wiphyname>). * It will be renamed automatically on wiphy renames * @dev: (virtual) struct device for this wiphy. The item in @@ -5033,6 +5035,7 @@ struct wiphy { struct device dev; bool registered; + bool registering; struct dentry *debugfsdir; 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); -- 2.26.2