diff options
Diffstat (limited to 'package/kernel/mac80211/patches/ath11k/0062-wifi-ath11k-fix-double-free-of-peer-rx_tid-during-re.patch')
-rw-r--r-- | package/kernel/mac80211/patches/ath11k/0062-wifi-ath11k-fix-double-free-of-peer-rx_tid-during-re.patch | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/ath11k/0062-wifi-ath11k-fix-double-free-of-peer-rx_tid-during-re.patch b/package/kernel/mac80211/patches/ath11k/0062-wifi-ath11k-fix-double-free-of-peer-rx_tid-during-re.patch new file mode 100644 index 0000000000..dd37b1e4fa --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0062-wifi-ath11k-fix-double-free-of-peer-rx_tid-during-re.patch @@ -0,0 +1,144 @@ +From 93a91f40c25c3d0e61f8540a7accf105090f9995 Mon Sep 17 00:00:00 2001 +From: Harshitha Prem <quic_hprem@quicinc.com> +Date: Mon, 17 Apr 2023 13:35:00 +0300 +Subject: [PATCH] wifi: ath11k: fix double free of peer rx_tid during reo cmd + failure + +Peer rx_tid is locally copied thrice during peer_rx_tid_cleanup to +send REO_CMD_UPDATE_RX_QUEUE followed by REO_CMD_FLUSH_CACHE to flush +all aged REO descriptors from HW cache. + +When sending REO_CMD_FLUSH_CACHE fails, we do dma unmap of already +mapped rx_tid->vaddr and free it. This is not checked during +reo_cmd_list_cleanup() and dp_reo_cmd_free() before trying to free and +unmap again. + +Fix this by setting rx_tid->vaddr NULL in rx tid delete and also +wherever freeing it to check in reo_cmd_list_cleanup() and +reo_cmd_free() before trying to free again. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Sathishkumar Muruganandam <quic_murugana@quicinc.com> +Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com> +Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com> +Link: https://lore.kernel.org/r/20230403182420.23375-2-quic_hprem@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 43 ++++++++++++++++++------- + 1 file changed, 31 insertions(+), 12 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -668,13 +668,18 @@ void ath11k_dp_reo_cmd_list_cleanup(stru + struct ath11k_dp *dp = &ab->dp; + struct dp_reo_cmd *cmd, *tmp; + struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache; ++ struct dp_rx_tid *rx_tid; + + spin_lock_bh(&dp->reo_cmd_lock); + list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { + list_del(&cmd->list); +- dma_unmap_single(ab->dev, cmd->data.paddr, +- cmd->data.size, DMA_BIDIRECTIONAL); +- kfree(cmd->data.vaddr); ++ rx_tid = &cmd->data; ++ if (rx_tid->vaddr) { ++ dma_unmap_single(ab->dev, rx_tid->paddr, ++ rx_tid->size, DMA_BIDIRECTIONAL); ++ kfree(rx_tid->vaddr); ++ rx_tid->vaddr = NULL; ++ } + kfree(cmd); + } + +@@ -682,9 +687,13 @@ void ath11k_dp_reo_cmd_list_cleanup(stru + &dp->reo_cmd_cache_flush_list, list) { + list_del(&cmd_cache->list); + dp->reo_cmd_cache_flush_count--; +- dma_unmap_single(ab->dev, cmd_cache->data.paddr, +- cmd_cache->data.size, DMA_BIDIRECTIONAL); +- kfree(cmd_cache->data.vaddr); ++ rx_tid = &cmd_cache->data; ++ if (rx_tid->vaddr) { ++ dma_unmap_single(ab->dev, rx_tid->paddr, ++ rx_tid->size, DMA_BIDIRECTIONAL); ++ kfree(rx_tid->vaddr); ++ rx_tid->vaddr = NULL; ++ } + kfree(cmd_cache); + } + spin_unlock_bh(&dp->reo_cmd_lock); +@@ -698,10 +707,12 @@ static void ath11k_dp_reo_cmd_free(struc + if (status != HAL_REO_CMD_SUCCESS) + ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n", + rx_tid->tid, status); +- +- dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size, +- DMA_BIDIRECTIONAL); +- kfree(rx_tid->vaddr); ++ if (rx_tid->vaddr) { ++ dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size, ++ DMA_BIDIRECTIONAL); ++ kfree(rx_tid->vaddr); ++ rx_tid->vaddr = NULL; ++ } + } + + static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, +@@ -740,6 +751,7 @@ static void ath11k_dp_reo_cache_flush(st + dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, + DMA_BIDIRECTIONAL); + kfree(rx_tid->vaddr); ++ rx_tid->vaddr = NULL; + } + } + +@@ -792,6 +804,7 @@ free_desc: + dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, + DMA_BIDIRECTIONAL); + kfree(rx_tid->vaddr); ++ rx_tid->vaddr = NULL; + } + + void ath11k_peer_rx_tid_delete(struct ath11k *ar, +@@ -804,6 +817,8 @@ void ath11k_peer_rx_tid_delete(struct at + if (!rx_tid->active) + return; + ++ rx_tid->active = false; ++ + cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; + cmd.addr_lo = lower_32_bits(rx_tid->paddr); + cmd.addr_hi = upper_32_bits(rx_tid->paddr); +@@ -818,9 +833,11 @@ void ath11k_peer_rx_tid_delete(struct at + dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size, + DMA_BIDIRECTIONAL); + kfree(rx_tid->vaddr); ++ rx_tid->vaddr = NULL; + } + +- rx_tid->active = false; ++ rx_tid->paddr = 0; ++ rx_tid->size = 0; + } + + static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab, +@@ -967,6 +984,7 @@ static void ath11k_dp_rx_tid_mem_free(st + dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, + DMA_BIDIRECTIONAL); + kfree(rx_tid->vaddr); ++ rx_tid->vaddr = NULL; + + rx_tid->active = false; + +@@ -1067,7 +1085,8 @@ int ath11k_peer_rx_tid_setup(struct ath1 + return ret; + + err_mem_free: +- kfree(vaddr); ++ kfree(rx_tid->vaddr); ++ rx_tid->vaddr = NULL; + + return ret; + } |