From: Felix Fietkau Date: Mon, 20 Nov 2017 19:05:19 +0000 (+0100) Subject: mac80211: fix a race condition that could lead to a use-after-free on a timer X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=6a6dc94e0c9a0533eaa9819bf3c22128b009af56;p=openwrt%2Fstaging%2Fluka.git mac80211: fix a race condition that could lead to a use-after-free on a timer Signed-off-by: Felix Fietkau --- diff --git a/package/kernel/mac80211/patches/320-mac80211-properly-free-requested-but-not-started-TX-.patch b/package/kernel/mac80211/patches/320-mac80211-properly-free-requested-but-not-started-TX-.patch new file mode 100644 index 0000000000..ecc5e49120 --- /dev/null +++ b/package/kernel/mac80211/patches/320-mac80211-properly-free-requested-but-not-started-TX-.patch @@ -0,0 +1,37 @@ +From: Johannes Berg +Date: Mon, 20 Nov 2017 17:01:44 +0100 +Subject: [PATCH] mac80211: properly free requested-but-not-started TX agg + sessions + +When deleting a station or otherwise tearing down all aggregation +sessions, make sure to delete requested but not yet started ones, +to avoid the following scenario: + + * session is requested, added to tid_start_tx[] + * ieee80211_ba_session_work() runs, gets past BLOCK_BA check + * ieee80211_sta_tear_down_BA_sessions() runs, locks &sta->ampdu_mlme.mtx, + e.g. while deleting the station - deleting all active sessions + * ieee80211_ba_session_work() continues since tear down flushes it, and + calls ieee80211_tx_ba_session_handle_start() for the new session, arms + the timer for it + * station deletion continues to __cleanup_single_sta() and frees the + session struct, while the timer is armed + +Reported-by: Fengguang Wu +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/agg-tx.c ++++ b/net/mac80211/agg-tx.c +@@ -330,6 +330,11 @@ int ___ieee80211_stop_tx_ba_session(stru + + spin_lock_bh(&sta->lock); + ++ /* free struct pending for start, if present */ ++ tid_tx = sta->ampdu_mlme.tid_start_tx[tid]; ++ kfree(tid_tx); ++ sta->ampdu_mlme.tid_start_tx[tid] = NULL; ++ + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); + if (!tid_tx) { + spin_unlock_bh(&sta->lock);