If firmware reports rate_max > WMI_TPC_RATE_MAX(WMI_TPC_FINAL_RATE_MAX)
or num_tx_chain > WMI_TPC_TX_N_CHAIN, it will cause array out-of-bounds
access, so print a warning and reset to avoid memory corruption.

Tested HW: QCA9984
Tested FW: 10.4-3.9.0.2-00035

Signed-off-by: Miaoqing Pan <miaoq...@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/debug.c |  2 +-
 drivers/net/wireless/ath/ath10k/wmi.c   | 49 +++++++++++++++++++++------------
 2 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index bd2b562..40baf25 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1516,7 +1516,7 @@ static void ath10k_tpc_stats_print(struct 
ath10k_tpc_stats *tpc_stats,
        *len += scnprintf(buf + *len, buf_len - *len,
                          "No.  Preamble Rate_code ");
 
-       for (i = 0; i < WMI_TPC_TX_N_CHAIN; i++)
+       for (i = 0; i < tpc_stats->num_tx_chain; i++)
                *len += scnprintf(buf + *len, buf_len - *len,
                                  "tpc_value%d ", i);
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index f0ab115..4473b13 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4681,16 +4681,13 @@ static void ath10k_tpc_config_disp_tables(struct ath10k 
*ar,
        }
 
        pream_idx = 0;
-       for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
+       for (i = 0; i < tpc_stats->rate_max; i++) {
                memset(tpc_value, 0, sizeof(tpc_value));
                memset(buff, 0, sizeof(buff));
                if (i == pream_table[pream_idx])
                        pream_idx++;
 
-               for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
-                       if (j >= __le32_to_cpu(ev->num_tx_chain))
-                               break;
-
+               for (j = 0; j < tpc_stats->num_tx_chain; j++) {
                        tpc[j] = ath10k_tpc_config_get_rate(ar, ev, i, j + 1,
                                                            rate_code[i],
                                                            type);
@@ -4803,7 +4800,7 @@ void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, 
u16 *pream_table,
 
 void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
 {
-       u32 num_tx_chain;
+       u32 num_tx_chain, rate_max;
        u8 rate_code[WMI_TPC_RATE_MAX];
        u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
        struct wmi_pdev_tpc_config_event *ev;
@@ -4819,6 +4816,13 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, 
struct sk_buff *skb)
                return;
        }
 
+       rate_max = __le32_to_cpu(ev->rate_max);
+       if (rate_max > WMI_TPC_RATE_MAX) {
+               ath10k_warn(ar, "number of rate is %d greater than TPC 
configured rate %d\n",
+                           rate_max, WMI_TPC_RATE_MAX);
+               rate_max = WMI_TPC_RATE_MAX;
+       }
+
        tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
        if (!tpc_stats)
                return;
@@ -4835,8 +4839,8 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, 
struct sk_buff *skb)
                __le32_to_cpu(ev->twice_antenna_reduction);
        tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
        tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
-       tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
-       tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
+       tpc_stats->num_tx_chain = num_tx_chain;
+       tpc_stats->rate_max = rate_max;
 
        ath10k_tpc_config_disp_tables(ar, ev, tpc_stats,
                                      rate_code, pream_table,
@@ -5031,16 +5035,13 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k 
*ar, struct sk_buff *skb)
        }
 
        pream_idx = 0;
-       for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
+       for (i = 0; i < tpc_stats->rate_max; i++) {
                memset(tpc_value, 0, sizeof(tpc_value));
                memset(buff, 0, sizeof(buff));
                if (i == pream_table[pream_idx])
                        pream_idx++;
 
-               for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
-                       if (j >= __le32_to_cpu(ev->num_tx_chain))
-                               break;
-
+               for (j = 0; j < tpc_stats->num_tx_chain; j++) {
                        tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1,
                                                               rate_code[i],
                                                               type, pream_idx);
@@ -5056,7 +5057,7 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, 
struct sk_buff *skb)
 
 void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb)
 {
-       u32 num_tx_chain;
+       u32 num_tx_chain, rate_max;
        u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
        u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
        struct wmi_pdev_tpc_final_table_event *ev;
@@ -5064,12 +5065,24 @@ void ath10k_wmi_event_tpc_final_table(struct ath10k 
*ar, struct sk_buff *skb)
 
        ev = (struct wmi_pdev_tpc_final_table_event *)skb->data;
 
+       num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
+       if (num_tx_chain > WMI_TPC_TX_N_CHAIN) {
+               ath10k_warn(ar, "number of tx chain is %d greater than TPC 
final configured tx chain %d\n",
+                           num_tx_chain, WMI_TPC_TX_N_CHAIN);
+               return;
+       }
+
+       rate_max = __le32_to_cpu(ev->rate_max);
+       if (rate_max > WMI_TPC_FINAL_RATE_MAX) {
+               ath10k_warn(ar, "number of rate is %d greater than TPC final 
configured rate %d\n",
+                           rate_max, WMI_TPC_FINAL_RATE_MAX);
+               rate_max = WMI_TPC_FINAL_RATE_MAX;
+       }
+
        tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
        if (!tpc_stats)
                return;
 
-       num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
-
        ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
                                            num_tx_chain);
 
@@ -5082,8 +5095,8 @@ void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, 
struct sk_buff *skb)
                __le32_to_cpu(ev->twice_antenna_reduction);
        tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
        tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
-       tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
-       tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
+       tpc_stats->num_tx_chain = num_tx_chain;
+       tpc_stats->rate_max = rate_max;
 
        ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
                                               rate_code, pream_table,
-- 
1.9.1


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

Reply via email to