]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ath10k: fix tx_stats memory leak
authorZhi Chen <zhichen@codeaurora.org>
Thu, 20 Dec 2018 12:25:18 +0000 (14:25 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Feb 2019 19:02:25 +0000 (20:02 +0100)
[ Upstream commit 386f97e3b201d18578abb0e7037b85a1ae50c0a3 ]

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>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/ath/ath10k/mac.c

index 6436dc229be5dbd892bc05e5e4788a9630b49214..400495858e4e94ee247a2734717667faf9f88152 100644 (file)
@@ -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;