| From 74cf8d0754a9ccb3f4a5cb1c5a33993a0f769d58 Mon Sep 17 00:00:00 2001 |
| From: Johannes Berg <johannes.berg@intel.com> |
| Date: Tue, 18 Oct 2016 23:12:08 +0300 |
| Subject: [PATCH] mac80211: fix tid_agg_rx NULL dereference |
| |
| commit 1c3d185a9a0b136a58e73b02912d593d0303d1da upstream. |
| |
| On drivers setting the SUPPORTS_REORDERING_BUFFER hardware flag, |
| we crash when the peer sends an AddBA request while we already |
| have a session open on the seame TID; this is because on those |
| drivers, the tid_agg_rx is left NULL even though the session is |
| valid, and the agg_session_valid bit is set. |
| |
| To fix this, store the dialog tokens outside the tid_agg_rx to |
| be able to compare them to the received AddBA request. |
| |
| Fixes: f89e07d4cf26 ("mac80211: agg-rx: refuse ADDBA Request with timeout update") |
| Reported-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| [PG: fixup surrounding context for lack of 1st chunk of bfe40fa395dd in 4.9] |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c |
| index afa94687d5e1..d309e26a8ec4 100644 |
| --- a/net/mac80211/agg-rx.c |
| +++ b/net/mac80211/agg-rx.c |
| @@ -312,11 +312,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, |
| mutex_lock(&sta->ampdu_mlme.mtx); |
| |
| if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) { |
| - tid_agg_rx = rcu_dereference_protected( |
| - sta->ampdu_mlme.tid_rx[tid], |
| - lockdep_is_held(&sta->ampdu_mlme.mtx)); |
| - |
| - if (tid_agg_rx->dialog_token == dialog_token) { |
| + if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) { |
| ht_dbg_ratelimited(sta->sdata, |
| "updated AddBA Req from %pM on tid %u\n", |
| sta->sta.addr, tid); |
| @@ -393,7 +389,6 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, |
| } |
| |
| /* update data */ |
| - tid_agg_rx->dialog_token = dialog_token; |
| tid_agg_rx->ssn = start_seq_num; |
| tid_agg_rx->head_seq_num = start_seq_num; |
| tid_agg_rx->buf_size = buf_size; |
| @@ -412,8 +407,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, |
| } |
| |
| end: |
| - if (status == WLAN_STATUS_SUCCESS) |
| + if (status == WLAN_STATUS_SUCCESS) { |
| __set_bit(tid, sta->ampdu_mlme.agg_session_valid); |
| + sta->ampdu_mlme.tid_rx_token[tid] = dialog_token; |
| + } |
| mutex_unlock(&sta->ampdu_mlme.mtx); |
| |
| end_no_lock: |
| diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c |
| index fd334133ff45..743dc631962f 100644 |
| --- a/net/mac80211/debugfs_sta.c |
| +++ b/net/mac80211/debugfs_sta.c |
| @@ -156,7 +156,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, |
| p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); |
| p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_rx); |
| p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
| - tid_rx ? tid_rx->dialog_token : 0); |
| + tid_rx ? sta->ampdu_mlme.tid_rx_token[i] : 0); |
| p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", |
| tid_rx ? tid_rx->ssn : 0); |
| |
| diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h |
| index 78b0ef32dddd..01708c85ec3c 100644 |
| --- a/net/mac80211/sta_info.h |
| +++ b/net/mac80211/sta_info.h |
| @@ -184,7 +184,6 @@ struct tid_ampdu_tx { |
| * @ssn: Starting Sequence Number expected to be aggregated. |
| * @buf_size: buffer size for incoming A-MPDUs |
| * @timeout: reset timer value (in TUs). |
| - * @dialog_token: dialog token for aggregation session |
| * @rcu_head: RCU head used for freeing this struct |
| * @reorder_lock: serializes access to reorder buffer, see below. |
| * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and |
| @@ -213,7 +212,6 @@ struct tid_ampdu_rx { |
| u16 ssn; |
| u16 buf_size; |
| u16 timeout; |
| - u8 dialog_token; |
| bool auto_seq; |
| bool removed; |
| }; |
| @@ -225,6 +223,7 @@ struct tid_ampdu_rx { |
| * to tid_tx[idx], which are protected by the sta spinlock) |
| * tid_start_tx is also protected by sta->lock. |
| * @tid_rx: aggregation info for Rx per TID -- RCU protected |
| + * @tid_rx_token: dialog tokens for valid aggregation sessions |
| * @tid_rx_timer_expired: bitmap indicating on which TIDs the |
| * RX timer expired until the work for it runs |
| * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the |
| @@ -241,6 +240,7 @@ struct sta_ampdu_mlme { |
| struct mutex mtx; |
| /* rx */ |
| struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; |
| + u8 tid_rx_token[IEEE80211_NUM_TIDS]; |
| unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
| unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
| unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
| -- |
| 2.10.1 |
| |