Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757276AbbFPJEQ (ORCPT ); Tue, 16 Jun 2015 05:04:16 -0400 Received: from mail.kernel.org ([198.145.29.136]:56726 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932667AbbFPIsb (ORCPT ); Tue, 16 Jun 2015 04:48:31 -0400 From: lizf@kernel.org To: stable@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Johannes Berg , Zefan Li Subject: [PATCH 3.4 140/172] mac80211: fix RX A-MPDU session reorder timer deletion Date: Tue, 16 Jun 2015 16:36:34 +0800 Message-Id: <1434443826-4929-140-git-send-email-lizf@kernel.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1434443587-4599-1-git-send-email-lizf@kernel.org> References: <1434443587-4599-1-git-send-email-lizf@kernel.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3831 Lines: 113 From: Johannes Berg 3.4.108-rc1 review patch. If anyone has any objections, please let me know. ------------------ commit 788211d81bfdf9b6a547d0530f206ba6ee76b107 upstream. There's an issue with the way the RX A-MPDU reorder timer is deleted that can cause a kernel crash like this: * tid_rx is removed - call_rcu(ieee80211_free_tid_rx) * station is destroyed * reorder timer fires before ieee80211_free_tid_rx() runs, accessing the station, thus potentially crashing due to the use-after-free The station deletion is protected by synchronize_net(), but that isn't enough -- ieee80211_free_tid_rx() need not have run when that returns (it deletes the timer.) We could use rcu_barrier() instead of synchronize_net(), but that's much more expensive. Instead, to fix this, add a field tracking that the session is being deleted. In this case, the only re-arming of the timer happens with the reorder spinlock held, so make that code not rearm it if the session is being deleted and also delete the timer after setting that field. This ensures the timer cannot fire after ___ieee80211_stop_rx_ba_session() returns, which fixes the problem. Signed-off-by: Johannes Berg [lizf: Backported to 3.4: adjust context] Signed-off-by: Zefan Li --- net/mac80211/agg-rx.c | 8 ++++++-- net/mac80211/rx.c | 7 ++++--- net/mac80211/sta_info.h | 2 ++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 64d3ce5..df2b6ac 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -49,8 +49,6 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) container_of(h, struct tid_ampdu_rx, rcu_head); int i; - del_timer_sync(&tid_rx->reorder_timer); - for (i = 0; i < tid_rx->buf_size; i++) dev_kfree_skb(tid_rx->reorder_buf[i]); kfree(tid_rx->reorder_buf); @@ -94,6 +92,12 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, del_timer_sync(&tid_rx->session_timer); + /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */ + spin_lock_bh(&tid_rx->reorder_lock); + tid_rx->removed = true; + spin_unlock_bh(&tid_rx->reorder_lock); + del_timer_sync(&tid_rx->reorder_timer); + call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index dcd632f..6202d05 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -668,9 +668,10 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, set_release_timer: - mod_timer(&tid_agg_rx->reorder_timer, - tid_agg_rx->reorder_time[j] + 1 + - HT_RX_REORDER_BUF_TIMEOUT); + if (!tid_agg_rx->removed) + mod_timer(&tid_agg_rx->reorder_timer, + tid_agg_rx->reorder_time[j] + 1 + + HT_RX_REORDER_BUF_TIMEOUT); } else { del_timer(&tid_agg_rx->reorder_timer); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 249f4d0..4e6ece8 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -106,6 +106,7 @@ enum ieee80211_sta_info_flags { * @buf_size: reorder buffer size at receiver * @failed_bar_ssn: ssn of the last failed BAR tx attempt * @bar_pending: BAR needs to be re-sent + * @removed: this session is removed (but might have been found due to RCU) * * This structure's lifetime is managed by RCU, assignments to * the array holding it must hold the aggregation mutex. @@ -169,6 +170,7 @@ struct tid_ampdu_rx { u16 buf_size; u16 timeout; u8 dialog_token; + bool removed; }; /** -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/