mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-19 18:31:33 +00:00
77 lines
2.9 KiB
Diff
77 lines
2.9 KiB
Diff
From e2e678b776705f63ef5421e3d65883b404e55ef2 Mon Sep 17 00:00:00 2001
|
|
From: Johannes Berg <johannes.berg@intel.com>
|
|
Date: Wed, 19 May 2021 15:11:49 +0530
|
|
Subject: [PATCH] mac80211: fix deadlock in AP/VLAN handling
|
|
|
|
Syzbot reports that when you have AP_VLAN interfaces that are up
|
|
and close the AP interface they belong to, we get a deadlock. No
|
|
surprise - since we dev_close() them with the wiphy mutex held,
|
|
which goes back into the netdev notifier in cfg80211 and tries to
|
|
acquire the wiphy mutex there.
|
|
|
|
To fix this, we need to do two things:
|
|
1) prevent changing iftype while AP_VLANs are up, we can't
|
|
easily fix this case since cfg80211 already calls us with
|
|
the wiphy mutex held, but change_interface() is relatively
|
|
rare in drivers anyway, so changing iftype isn't used much
|
|
(and userspace has to fall back to down/change/up anyway)
|
|
2) pull the dev_close() loop over VLANs out of the wiphy mutex
|
|
section in the normal stop case
|
|
|
|
Fixes: a05829a7222e ("cfg80211: avoid holding the RTNL when calling the driver")
|
|
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
|
Signed-off-by: Seevalamuthu Mariappan <seevalam@codeaurora.org>
|
|
---
|
|
net/mac80211/iface.c | 20 +++++++++++++-------
|
|
1 file changed, 13 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
|
|
index 20327cf..c6f79ce 100644
|
|
--- a/net/mac80211/iface.c
|
|
+++ b/net/mac80211/iface.c
|
|
@@ -491,14 +491,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
|
|
|
cancel_work_sync(&sdata->color_change_finalize_work);
|
|
|
|
- /* APs need special treatment */
|
|
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
|
- struct ieee80211_sub_if_data *vlan, *tmpsdata;
|
|
-
|
|
- /* down all dependent devices, that is VLANs */
|
|
- list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
|
|
- u.vlan.list)
|
|
- dev_close(vlan->dev);
|
|
WARN_ON(!list_empty(&sdata->u.ap.vlans));
|
|
} else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
|
/* remove all packets in parent bc_buf pointing to this dev */
|
|
@@ -659,6 +652,16 @@ static int ieee80211_stop(struct net_device *dev)
|
|
{
|
|
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
|
|
+ /* close all dependent VLAN interfaces before locking wiphy */
|
|
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
|
+ struct ieee80211_sub_if_data *vlan, *tmpsdata;
|
|
+
|
|
+ /* down all dependent devices, that is VLANs */
|
|
+ list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
|
|
+ u.vlan.list)
|
|
+ dev_close(vlan->dev);
|
|
+ }
|
|
+
|
|
wiphy_lock(sdata->local->hw.wiphy);
|
|
if (sdata->nssctx) {
|
|
nss_virt_if_destroy_sync(sdata->nssctx);
|
|
@@ -1746,6 +1749,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
|
|
|
|
switch (sdata->vif.type) {
|
|
case NL80211_IFTYPE_AP:
|
|
+ if (!list_empty(&sdata->u.ap.vlans))
|
|
+ return -EBUSY;
|
|
+ break;
|
|
case NL80211_IFTYPE_STATION:
|
|
case NL80211_IFTYPE_ADHOC:
|
|
case NL80211_IFTYPE_OCB:
|
|
--
|
|
2.7.4
|
|
|