summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2021-01-22 19:11:16 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-02-04 01:16:17 +0300
commit9f1f71f1d4bdf2003780e40a20cf0dea5900a182 (patch)
tree40612eae2917b8c76064bb37fcc35c2b063f33c0
parent8b97c8c934c81583ced691c6116f932060580185 (diff)
downloadlinux-9f1f71f1d4bdf2003780e40a20cf0dea5900a182.tar.xz
mac80211: pause TX while changing interface type
[ Upstream commit 054c9939b4800a91475d8d89905827bf9e1ad97a ] syzbot reported a crash that happened when changing the interface type around a lot, and while it might have been easy to fix just the symptom there, a little deeper investigation found that really the reason is that we allowed packets to be transmitted while in the middle of changing the interface type. Disallow TX by stopping the queues while changing the type. Fixes: 34d4bc4d41d2 ("mac80211: support runtime interface type changes") Reported-by: syzbot+d7a3b15976bf7de2238a@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20210122171115.b321f98f4d4f.I6997841933c17b093535c31d29355be3c0c39628@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/iface.c6
2 files changed, 7 insertions, 0 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a991d1df6774..1046520d726d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1027,6 +1027,7 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_FLUSH,
IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN,
IEEE80211_QUEUE_STOP_REASON_RESERVE_TID,
+ IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE,
IEEE80211_QUEUE_STOP_REASONS,
};
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 519def0e15f1..6d12a893eb11 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1507,6 +1507,10 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
if (ret)
return ret;
+ ieee80211_stop_vif_queues(local, sdata,
+ IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
+ synchronize_net();
+
ieee80211_do_stop(sdata, false);
ieee80211_teardown_sdata(sdata);
@@ -1527,6 +1531,8 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
err = ieee80211_do_open(&sdata->wdev, false);
WARN(err, "type change: do_open returned %d", err);
+ ieee80211_wake_vif_queues(local, sdata,
+ IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
return ret;
}