diff --git a/debian/changelog b/debian/changelog index c259cf052..f0e057fe6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,8 @@ linux (4.13.4-2) UNRELEASED; urgency=medium * [powerpc*] Use emergency stack for kernel TM Bad Thing program (CVE-2017-1000255) * [powerpc*] Fix illegal TM state in signal handler + * mac80211: fix deadlock in driver-managed RX BA session start. + Thanks to Eric Côté (Closes: #878092) -- Ben Hutchings Wed, 04 Oct 2017 23:14:54 +0100 diff --git a/debian/patches/bugfix/all/mac80211-fix-deadlock-in-driver-managed-RX-BA-sessio.patch b/debian/patches/bugfix/all/mac80211-fix-deadlock-in-driver-managed-RX-BA-sessio.patch new file mode 100644 index 000000000..1a7fff92c --- /dev/null +++ b/debian/patches/bugfix/all/mac80211-fix-deadlock-in-driver-managed-RX-BA-sessio.patch @@ -0,0 +1,151 @@ +From: Johannes Berg +Date: Wed, 6 Sep 2017 15:01:42 +0200 +Subject: mac80211: fix deadlock in driver-managed RX BA session start +Origin: https://git.kernel.org/linus/bde59c475e0883e4c4294bcd9b9c7e08ae18c828 +Bug-Debian: https://bugs.debian.org/878092 + +When an RX BA session is started by the driver, and it has to tell +mac80211 about it, the corresponding bit in tid_rx_manage_offl gets +set and the BA session work is scheduled. Upon testing this bit, it +will call __ieee80211_start_rx_ba_session(), thus deadlocking as it +already holds the ampdu_mlme.mtx, which that acquires again. + +Fix this by adding ___ieee80211_start_rx_ba_session(), a version of +the function that requires the mutex already held. + +Cc: stable@vger.kernel.org +Fixes: 699cb58c8a52 ("mac80211: manage RX BA session offload without SKB queue") +Reported-by: Matteo Croce +Signed-off-by: Johannes Berg +--- + net/mac80211/agg-rx.c | 32 +++++++++++++++++++++----------- + net/mac80211/ht.c | 6 +++--- + net/mac80211/ieee80211_i.h | 4 ++++ + 3 files changed, 28 insertions(+), 14 deletions(-) + +diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c +index 2b36eff5d97e..2849a1fc41c5 100644 +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -245,10 +245,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d + ieee80211_tx_skb(sdata, skb); + } + +-void __ieee80211_start_rx_ba_session(struct sta_info *sta, +- u8 dialog_token, u16 timeout, +- u16 start_seq_num, u16 ba_policy, u16 tid, +- u16 buf_size, bool tx, bool auto_seq) ++void ___ieee80211_start_rx_ba_session(struct sta_info *sta, ++ u8 dialog_token, u16 timeout, ++ u16 start_seq_num, u16 ba_policy, u16 tid, ++ u16 buf_size, bool tx, bool auto_seq) + { + struct ieee80211_local *local = sta->sdata->local; + struct tid_ampdu_rx *tid_agg_rx; +@@ -267,7 +267,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + ht_dbg(sta->sdata, + "STA %pM requests BA session on unsupported tid %d\n", + sta->sta.addr, tid); +- goto end_no_lock; ++ goto end; + } + + if (!sta->sta.ht_cap.ht_supported) { +@@ -275,14 +275,14 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + "STA %pM erroneously requests BA session on tid %d w/o QoS\n", + sta->sta.addr, tid); + /* send a response anyway, it's an error case if we get here */ +- goto end_no_lock; ++ goto end; + } + + if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { + ht_dbg(sta->sdata, + "Suspend in progress - Denying ADDBA request (%pM tid %d)\n", + sta->sta.addr, tid); +- goto end_no_lock; ++ goto end; + } + + /* sanity check for incoming parameters: +@@ -296,7 +296,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + ht_dbg_ratelimited(sta->sdata, + "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", + sta->sta.addr, tid, ba_policy, buf_size); +- goto end_no_lock; ++ goto end; + } + /* determine default buffer size */ + if (buf_size == 0) +@@ -311,7 +311,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + buf_size, sta->sta.addr); + + /* examine state machine */ +- mutex_lock(&sta->ampdu_mlme.mtx); ++ lockdep_assert_held(&sta->ampdu_mlme.mtx); + + if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) { + if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) { +@@ -415,15 +415,25 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + __clear_bit(tid, sta->ampdu_mlme.unexpected_agg); + sta->ampdu_mlme.tid_rx_token[tid] = dialog_token; + } +- mutex_unlock(&sta->ampdu_mlme.mtx); + +-end_no_lock: + if (tx) + ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, + dialog_token, status, 1, buf_size, + timeout); + } + ++void __ieee80211_start_rx_ba_session(struct sta_info *sta, ++ u8 dialog_token, u16 timeout, ++ u16 start_seq_num, u16 ba_policy, u16 tid, ++ u16 buf_size, bool tx, bool auto_seq) ++{ ++ mutex_lock(&sta->ampdu_mlme.mtx); ++ ___ieee80211_start_rx_ba_session(sta, dialog_token, timeout, ++ start_seq_num, ba_policy, tid, ++ buf_size, tx, auto_seq); ++ mutex_unlock(&sta->ampdu_mlme.mtx); ++} ++ + void ieee80211_process_addba_request(struct ieee80211_local *local, + struct sta_info *sta, + struct ieee80211_mgmt *mgmt, +diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c +index 4cba7fca10d4..d6d0b4201e40 100644 +--- a/net/mac80211/ht.c ++++ b/net/mac80211/ht.c +@@ -351,9 +351,9 @@ void ieee80211_ba_session_work(struct work_struct *work) + + if (test_and_clear_bit(tid, + sta->ampdu_mlme.tid_rx_manage_offl)) +- __ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid, +- IEEE80211_MAX_AMPDU_BUF, +- false, true); ++ ___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid, ++ IEEE80211_MAX_AMPDU_BUF, ++ false, true); + + if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS, + sta->ampdu_mlme.tid_rx_manage_offl)) +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index 2197c62a0a6e..9675814f64db 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1760,6 +1760,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + u8 dialog_token, u16 timeout, + u16 start_seq_num, u16 ba_policy, u16 tid, + u16 buf_size, bool tx, bool auto_seq); ++void ___ieee80211_start_rx_ba_session(struct sta_info *sta, ++ u8 dialog_token, u16 timeout, ++ u16 start_seq_num, u16 ba_policy, u16 tid, ++ u16 buf_size, bool tx, bool auto_seq); + void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, + enum ieee80211_agg_stop_reason reason); + void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, +-- +2.15.0.rc0 + diff --git a/debian/patches/series b/debian/patches/series index 9a974070f..01ec97378 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -78,6 +78,7 @@ bugfix/all/fs-add-module_softdep-declarations-for-hard-coded-cr.patch bugfix/all/partially-revert-usb-kconfig-using-select-for-usb_co.patch bugfix/all/kbuild-include-addtree-remove-quotes-before-matching-path.patch bugfix/all/bfq-re-enable-auto-loading-when-built-as-a-module.patch +bugfix/all/mac80211-fix-deadlock-in-driver-managed-RX-BA-sessio.patch # Miscellaneous features