2020-09-22 20:59:34

by Ben Greear

[permalink] [raw]
Subject: [PATCH] mac80211: Remove vdevs from driver when firmware is unrecoverable.

From: Ben Greear <[email protected]>

While testing ax200 (backport version hacked into a 5.4 kernel),
I noticed a KASAN use-after-free. I think this is because the
old logic would clear the SDATA_IN_DRIVER flag without actually
removing it from the driver. Then a bit later, the driver would
try to access some sdata memory.

So instead, tell the driver to remove the vdevs. The kernel still
splats a lot of warnings in this case, but I did not see a KASAN
error and the system recovered and continued running on the remaining
radio (the one w/out fatal firmware error).

Signed-off-by: Ben Greear <[email protected]>
---
net/mac80211/util.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ecd56f80b0c82..320e3df9ac31c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2070,7 +2070,7 @@ static void ieee80211_flush_completed_scan(struct ieee80211_local *local,

static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata, *sdata_tmp;
struct ieee80211_chanctx *ctx;

/*
@@ -2094,8 +2094,9 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
*/
ieee80211_sched_scan_end(local);

- list_for_each_entry(sdata, &local->interfaces, list)
- sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
+ list_for_each_entry_safe(sdata, sdata_tmp, &local->interfaces, list)
+ if (check_sdata_in_driver(sdata))
+ drv_remove_interface(local, sdata);

/* Mark channel contexts as not being in the driver any more to avoid
* removing them from the driver during the shutdown process...
@@ -2306,12 +2307,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
* report failure.
*/
if (res) {
- list_for_each_entry_continue_reverse(sdata, &local->interfaces,
- list)
- if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- sdata->vif.type != NL80211_IFTYPE_MONITOR &&
- ieee80211_sdata_running(sdata))
- drv_remove_interface(local, sdata);
ieee80211_handle_reconfig_failure(local);
return res;
}
--
2.26.2