linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 1/2] ath10k: fix peer stats null pointer dereference
@ 2018-12-11  3:08 zhichen
  2018-12-11  3:08 ` [PATCH v1 2/2] ath10k: fix tx_stats memory leak zhichen
  2018-12-20 17:09 ` [PATCH v1 1/2] ath10k: fix peer stats null pointer dereference Kalle Valo
  0 siblings, 2 replies; 3+ messages in thread
From: zhichen @ 2018-12-11  3:08 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Zhi Chen

From: Zhi Chen <zhichen@codeaurora.org>

There was a race condition in SMP that an ath10k_peer was created but its
member sta was null. Following are procedures of ath10k_peer creation and
member sta access in peer statistics path.

    1. Peer creation:
        ath10k_peer_create()
            =>ath10k_wmi_peer_create()
                =>ath10k_wait_for_peer_created()
                ...

        # another kernel path, RX from firmware
        ath10k_htt_t2h_msg_handler()
        =>ath10k_peer_map_event()
                =>wake_up()
                # ar->peer_map[id] = peer //add peer to map

        #wake up original path from waiting
                ...
                # peer->sta = sta //sta assignment

    2.  RX path of statistics
        ath10k_htt_t2h_msg_handler()
            =>ath10k_update_per_peer_tx_stats()
                =>ath10k_htt_fetch_peer_stats()
                # peer->sta //sta accessing

Any access of peer->sta after peer was added to peer_map but before sta was
assigned could cause a null pointer issue. And because these two steps are
asynchronous, no proper lock can protect them. So both peer and sta need to
be checked before access.

Tested: QCA9984 with firmware ver 10.4-3.9.0.1-00005
Signed-off-by: Zhi Chen <zhichen@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/debugfs_sta.c | 2 +-
 drivers/net/wireless/ath/ath10k/htt_rx.c      | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index 0f3fd65..4778a45 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -71,7 +71,7 @@ void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid
 	spin_lock_bh(&ar->data_lock);
 
 	peer = ath10k_peer_find_by_id(ar, peer_id);
-	if (!peer)
+	if (!peer || !peer->sta)
 		goto out;
 
 	arsta = (struct ath10k_sta *)peer->sta->drv_priv;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 984b045..a1552f0 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2847,7 +2847,7 @@ static void ath10k_htt_fetch_peer_stats(struct ath10k *ar,
 	rcu_read_lock();
 	spin_lock_bh(&ar->data_lock);
 	peer = ath10k_peer_find_by_id(ar, peer_id);
-	if (!peer) {
+	if (!peer || !peer->sta) {
 		ath10k_warn(ar, "Invalid peer id %d peer stats buffer\n",
 			    peer_id);
 		goto out;
@@ -2900,7 +2900,7 @@ static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data)
 	rcu_read_lock();
 	spin_lock_bh(&ar->data_lock);
 	peer = ath10k_peer_find_by_id(ar, peer_id);
-	if (!peer) {
+	if (!peer || !peer->sta) {
 		ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n",
 			    peer_id);
 		goto out;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v1 2/2] ath10k: fix tx_stats memory leak
  2018-12-11  3:08 [PATCH v1 1/2] ath10k: fix peer stats null pointer dereference zhichen
@ 2018-12-11  3:08 ` zhichen
  2018-12-20 17:09 ` [PATCH v1 1/2] ath10k: fix peer stats null pointer dereference Kalle Valo
  1 sibling, 0 replies; 3+ messages in thread
From: zhichen @ 2018-12-11  3:08 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Zhi Chen

From: Zhi Chen <zhichen@codeaurora.org>

Memory of tx_stats was allocated when a STA was added. But it's not freed
if the STA failed to be added to driver. This issue could be seen in MDK3
attack case when STA number reached the limit.

Tested: QCA9984 with firmware ver 10.4-3.9.0.1-00005
Signed-off-by: Zhi Chen <zhichen@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/mac.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 1db2a30..001cf31 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -6293,15 +6293,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			   ar->num_stations + 1, ar->max_num_stations,
 			   ar->num_peers + 1, ar->max_num_peers);
 
-		if (ath10k_debug_is_extd_tx_stats_enabled(ar)) {
-			arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats),
-						  GFP_KERNEL);
-			if (!arsta->tx_stats) {
-				ret = -ENOMEM;
-				goto exit;
-			}
-		}
-
 		num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif);
 		num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw);
 
@@ -6323,12 +6314,22 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			goto exit;
 		}
 
+		if (ath10k_debug_is_extd_tx_stats_enabled(ar)) {
+			arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats),
+						  GFP_KERNEL);
+			if (!arsta->tx_stats) {
+				ret = -ENOMEM;
+				goto exit;
+			}
+		}
+
 		ret = ath10k_peer_create(ar, vif, sta, arvif->vdev_id,
 					 sta->addr, peer_type);
 		if (ret) {
 			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 			ath10k_mac_dec_num_stations(arvif, sta);
+			kfree(arsta->tx_stats);
 			goto exit;
 		}
 
@@ -6341,6 +6342,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			spin_unlock_bh(&ar->data_lock);
 			ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
 			ath10k_mac_dec_num_stations(arvif, sta);
+			kfree(arsta->tx_stats);
 			ret = -ENOENT;
 			goto exit;
 		}
@@ -6361,6 +6363,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 			ath10k_peer_delete(ar, arvif->vdev_id,
 					   sta->addr);
 			ath10k_mac_dec_num_stations(arvif, sta);
+			kfree(arsta->tx_stats);
 			goto exit;
 		}
 
@@ -6372,6 +6375,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 				    sta->addr, arvif->vdev_id, ret);
 			ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
 			ath10k_mac_dec_num_stations(arvif, sta);
+			kfree(arsta->tx_stats);
 
 			if (num_tdls_stations != 0)
 				goto exit;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v1 1/2] ath10k: fix peer stats null pointer dereference
  2018-12-11  3:08 [PATCH v1 1/2] ath10k: fix peer stats null pointer dereference zhichen
  2018-12-11  3:08 ` [PATCH v1 2/2] ath10k: fix tx_stats memory leak zhichen
@ 2018-12-20 17:09 ` Kalle Valo
  1 sibling, 0 replies; 3+ messages in thread
From: Kalle Valo @ 2018-12-20 17:09 UTC (permalink / raw)
  To: zhichen; +Cc: ath10k, linux-wireless, Zhi Chen

zhichen@codeaurora.org wrote:

> There was a race condition in SMP that an ath10k_peer was created but its
> member sta was null. Following are procedures of ath10k_peer creation and
> member sta access in peer statistics path.
> 
>     1. Peer creation:
>         ath10k_peer_create()
>             =>ath10k_wmi_peer_create()
>                 =>ath10k_wait_for_peer_created()
>                 ...
> 
>         # another kernel path, RX from firmware
>         ath10k_htt_t2h_msg_handler()
>         =>ath10k_peer_map_event()
>                 =>wake_up()
>                 # ar->peer_map[id] = peer //add peer to map
> 
>         #wake up original path from waiting
>                 ...
>                 # peer->sta = sta //sta assignment
> 
>     2.  RX path of statistics
>         ath10k_htt_t2h_msg_handler()
>             =>ath10k_update_per_peer_tx_stats()
>                 =>ath10k_htt_fetch_peer_stats()
>                 # peer->sta //sta accessing
> 
> Any access of peer->sta after peer was added to peer_map but before sta was
> assigned could cause a null pointer issue. And because these two steps are
> asynchronous, no proper lock can protect them. So both peer and sta need to
> be checked before access.
> 
> Tested: QCA9984 with firmware ver 10.4-3.9.0.1-00005
> Signed-off-by: Zhi Chen <zhichen@codeaurora.org>
> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>

2 patches applied to ath-next branch of ath.git, thanks.

2d3b55853b12 ath10k: fix peer stats null pointer dereference
386f97e3b201 ath10k: fix tx_stats memory leak

-- 
https://patchwork.kernel.org/patch/10722983/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-12-20 17:09 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-11  3:08 [PATCH v1 1/2] ath10k: fix peer stats null pointer dereference zhichen
2018-12-11  3:08 ` [PATCH v1 2/2] ath10k: fix tx_stats memory leak zhichen
2018-12-20 17:09 ` [PATCH v1 1/2] ath10k: fix peer stats null pointer dereference Kalle Valo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).