mac80211: pause TX while changing interface type
authorJohannes Berg <johannes.berg@intel.com>
Fri, 22 Jan 2021 16:11:16 +0000 (17:11 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Feb 2021 22:22:22 +0000 (23:22 +0100)
[ 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>
net/mac80211/ieee80211_i.h
net/mac80211/iface.c

index 0e209a88d88a78b54dbab8426999dd069f93dbb2..651705565dfb9d2b2147b2a9870b4c5c78dd18bc 100644 (file)
@@ -1047,6 +1047,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,
 };
index 6ce13e976b7a2cd4c4f46a3b486c7c67601b85f1..dc398a18167882efc73bc118dd6d47f8a4679d90 100644 (file)
@@ -1559,6 +1559,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);
@@ -1579,6 +1583,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;
 }