Commit ffca49e2 authored by Miaoqing Pan's avatar Miaoqing Pan Committed by Greg Kroah-Hartman

ath10k: fix array out-of-bounds access

[ Upstream commit c5329b2d ]

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: default avatarMiaoqing Pan <miaoqing@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 8e634b7b
......@@ -1521,7 +1521,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);
......
......@@ -4550,16 +4550,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);
......@@ -4672,7 +4669,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;
......@@ -4688,6 +4685,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;
......@@ -4704,8 +4708,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,
......@@ -4900,16 +4904,13 @@ ath10k_wmi_tpc_stats_final_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_wmi_tpc_final_get_rate(ar, ev, i, j + 1,
rate_code[i],
type, pream_idx);
......@@ -4925,7 +4926,7 @@ ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar,
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;
......@@ -4933,12 +4934,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);
......@@ -4951,8 +4964,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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment