Skip to content

Commit 93a91f4

Browse files
Harshitha Premkvalo
authored andcommitted
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
1 parent ed09c61 commit 93a91f4

1 file changed

Lines changed: 31 additions & 12 deletions

File tree

  • drivers/net/wireless/ath/ath11k

drivers/net/wireless/ath/ath11k/dp_rx.c

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -668,23 +668,32 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
668668
struct ath11k_dp *dp = &ab->dp;
669669
struct dp_reo_cmd *cmd, *tmp;
670670
struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache;
671+
struct dp_rx_tid *rx_tid;
671672

672673
spin_lock_bh(&dp->reo_cmd_lock);
673674
list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
674675
list_del(&cmd->list);
675-
dma_unmap_single(ab->dev, cmd->data.paddr,
676-
cmd->data.size, DMA_BIDIRECTIONAL);
677-
kfree(cmd->data.vaddr);
676+
rx_tid = &cmd->data;
677+
if (rx_tid->vaddr) {
678+
dma_unmap_single(ab->dev, rx_tid->paddr,
679+
rx_tid->size, DMA_BIDIRECTIONAL);
680+
kfree(rx_tid->vaddr);
681+
rx_tid->vaddr = NULL;
682+
}
678683
kfree(cmd);
679684
}
680685

681686
list_for_each_entry_safe(cmd_cache, tmp_cache,
682687
&dp->reo_cmd_cache_flush_list, list) {
683688
list_del(&cmd_cache->list);
684689
dp->reo_cmd_cache_flush_count--;
685-
dma_unmap_single(ab->dev, cmd_cache->data.paddr,
686-
cmd_cache->data.size, DMA_BIDIRECTIONAL);
687-
kfree(cmd_cache->data.vaddr);
690+
rx_tid = &cmd_cache->data;
691+
if (rx_tid->vaddr) {
692+
dma_unmap_single(ab->dev, rx_tid->paddr,
693+
rx_tid->size, DMA_BIDIRECTIONAL);
694+
kfree(rx_tid->vaddr);
695+
rx_tid->vaddr = NULL;
696+
}
688697
kfree(cmd_cache);
689698
}
690699
spin_unlock_bh(&dp->reo_cmd_lock);
@@ -698,10 +707,12 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx,
698707
if (status != HAL_REO_CMD_SUCCESS)
699708
ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
700709
rx_tid->tid, status);
701-
702-
dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
703-
DMA_BIDIRECTIONAL);
704-
kfree(rx_tid->vaddr);
710+
if (rx_tid->vaddr) {
711+
dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
712+
DMA_BIDIRECTIONAL);
713+
kfree(rx_tid->vaddr);
714+
rx_tid->vaddr = NULL;
715+
}
705716
}
706717

707718
static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
@@ -740,6 +751,7 @@ static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
740751
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
741752
DMA_BIDIRECTIONAL);
742753
kfree(rx_tid->vaddr);
754+
rx_tid->vaddr = NULL;
743755
}
744756
}
745757

@@ -792,6 +804,7 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
792804
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
793805
DMA_BIDIRECTIONAL);
794806
kfree(rx_tid->vaddr);
807+
rx_tid->vaddr = NULL;
795808
}
796809

797810
void ath11k_peer_rx_tid_delete(struct ath11k *ar,
@@ -804,6 +817,8 @@ void ath11k_peer_rx_tid_delete(struct ath11k *ar,
804817
if (!rx_tid->active)
805818
return;
806819

820+
rx_tid->active = false;
821+
807822
cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
808823
cmd.addr_lo = lower_32_bits(rx_tid->paddr);
809824
cmd.addr_hi = upper_32_bits(rx_tid->paddr);
@@ -818,9 +833,11 @@ void ath11k_peer_rx_tid_delete(struct ath11k *ar,
818833
dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
819834
DMA_BIDIRECTIONAL);
820835
kfree(rx_tid->vaddr);
836+
rx_tid->vaddr = NULL;
821837
}
822838

823-
rx_tid->active = false;
839+
rx_tid->paddr = 0;
840+
rx_tid->size = 0;
824841
}
825842

826843
static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
@@ -967,6 +984,7 @@ static void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab,
967984
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
968985
DMA_BIDIRECTIONAL);
969986
kfree(rx_tid->vaddr);
987+
rx_tid->vaddr = NULL;
970988

971989
rx_tid->active = false;
972990

@@ -1067,7 +1085,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
10671085
return ret;
10681086

10691087
err_mem_free:
1070-
kfree(vaddr);
1088+
kfree(rx_tid->vaddr);
1089+
rx_tid->vaddr = NULL;
10711090

10721091
return ret;
10731092
}

0 commit comments

Comments
 (0)