0062-wifi-ath11k-fix-double-free-of-peer-rx_tid-during-re.patch 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. From 93a91f40c25c3d0e61f8540a7accf105090f9995 Mon Sep 17 00:00:00 2001
  2. From: Harshitha Prem <quic_hprem@quicinc.com>
  3. Date: Mon, 17 Apr 2023 13:35:00 +0300
  4. Subject: [PATCH] wifi: ath11k: fix double free of peer rx_tid during reo cmd
  5. failure
  6. Peer rx_tid is locally copied thrice during peer_rx_tid_cleanup to
  7. send REO_CMD_UPDATE_RX_QUEUE followed by REO_CMD_FLUSH_CACHE to flush
  8. all aged REO descriptors from HW cache.
  9. When sending REO_CMD_FLUSH_CACHE fails, we do dma unmap of already
  10. mapped rx_tid->vaddr and free it. This is not checked during
  11. reo_cmd_list_cleanup() and dp_reo_cmd_free() before trying to free and
  12. unmap again.
  13. Fix this by setting rx_tid->vaddr NULL in rx tid delete and also
  14. wherever freeing it to check in reo_cmd_list_cleanup() and
  15. reo_cmd_free() before trying to free again.
  16. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
  17. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
  18. Signed-off-by: Sathishkumar Muruganandam <quic_murugana@quicinc.com>
  19. Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
  20. Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
  21. Link: https://lore.kernel.org/r/20230403182420.23375-2-quic_hprem@quicinc.com
  22. ---
  23. drivers/net/wireless/ath/ath11k/dp_rx.c | 43 ++++++++++++++++++-------
  24. 1 file changed, 31 insertions(+), 12 deletions(-)
  25. --- a/drivers/net/wireless/ath/ath11k/dp_rx.c
  26. +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
  27. @@ -668,13 +668,18 @@ void ath11k_dp_reo_cmd_list_cleanup(stru
  28. struct ath11k_dp *dp = &ab->dp;
  29. struct dp_reo_cmd *cmd, *tmp;
  30. struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache;
  31. + struct dp_rx_tid *rx_tid;
  32. spin_lock_bh(&dp->reo_cmd_lock);
  33. list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
  34. list_del(&cmd->list);
  35. - dma_unmap_single(ab->dev, cmd->data.paddr,
  36. - cmd->data.size, DMA_BIDIRECTIONAL);
  37. - kfree(cmd->data.vaddr);
  38. + rx_tid = &cmd->data;
  39. + if (rx_tid->vaddr) {
  40. + dma_unmap_single(ab->dev, rx_tid->paddr,
  41. + rx_tid->size, DMA_BIDIRECTIONAL);
  42. + kfree(rx_tid->vaddr);
  43. + rx_tid->vaddr = NULL;
  44. + }
  45. kfree(cmd);
  46. }
  47. @@ -682,9 +687,13 @@ void ath11k_dp_reo_cmd_list_cleanup(stru
  48. &dp->reo_cmd_cache_flush_list, list) {
  49. list_del(&cmd_cache->list);
  50. dp->reo_cmd_cache_flush_count--;
  51. - dma_unmap_single(ab->dev, cmd_cache->data.paddr,
  52. - cmd_cache->data.size, DMA_BIDIRECTIONAL);
  53. - kfree(cmd_cache->data.vaddr);
  54. + rx_tid = &cmd_cache->data;
  55. + if (rx_tid->vaddr) {
  56. + dma_unmap_single(ab->dev, rx_tid->paddr,
  57. + rx_tid->size, DMA_BIDIRECTIONAL);
  58. + kfree(rx_tid->vaddr);
  59. + rx_tid->vaddr = NULL;
  60. + }
  61. kfree(cmd_cache);
  62. }
  63. spin_unlock_bh(&dp->reo_cmd_lock);
  64. @@ -698,10 +707,12 @@ static void ath11k_dp_reo_cmd_free(struc
  65. if (status != HAL_REO_CMD_SUCCESS)
  66. ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
  67. rx_tid->tid, status);
  68. -
  69. - dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
  70. - DMA_BIDIRECTIONAL);
  71. - kfree(rx_tid->vaddr);
  72. + if (rx_tid->vaddr) {
  73. + dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
  74. + DMA_BIDIRECTIONAL);
  75. + kfree(rx_tid->vaddr);
  76. + rx_tid->vaddr = NULL;
  77. + }
  78. }
  79. static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
  80. @@ -740,6 +751,7 @@ static void ath11k_dp_reo_cache_flush(st
  81. dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
  82. DMA_BIDIRECTIONAL);
  83. kfree(rx_tid->vaddr);
  84. + rx_tid->vaddr = NULL;
  85. }
  86. }
  87. @@ -792,6 +804,7 @@ free_desc:
  88. dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
  89. DMA_BIDIRECTIONAL);
  90. kfree(rx_tid->vaddr);
  91. + rx_tid->vaddr = NULL;
  92. }
  93. void ath11k_peer_rx_tid_delete(struct ath11k *ar,
  94. @@ -804,6 +817,8 @@ void ath11k_peer_rx_tid_delete(struct at
  95. if (!rx_tid->active)
  96. return;
  97. + rx_tid->active = false;
  98. +
  99. cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
  100. cmd.addr_lo = lower_32_bits(rx_tid->paddr);
  101. cmd.addr_hi = upper_32_bits(rx_tid->paddr);
  102. @@ -818,9 +833,11 @@ void ath11k_peer_rx_tid_delete(struct at
  103. dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
  104. DMA_BIDIRECTIONAL);
  105. kfree(rx_tid->vaddr);
  106. + rx_tid->vaddr = NULL;
  107. }
  108. - rx_tid->active = false;
  109. + rx_tid->paddr = 0;
  110. + rx_tid->size = 0;
  111. }
  112. static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
  113. @@ -967,6 +984,7 @@ static void ath11k_dp_rx_tid_mem_free(st
  114. dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
  115. DMA_BIDIRECTIONAL);
  116. kfree(rx_tid->vaddr);
  117. + rx_tid->vaddr = NULL;
  118. rx_tid->active = false;
  119. @@ -1067,7 +1085,8 @@ int ath11k_peer_rx_tid_setup(struct ath1
  120. return ret;
  121. err_mem_free:
  122. - kfree(vaddr);
  123. + kfree(rx_tid->vaddr);
  124. + rx_tid->vaddr = NULL;
  125. return ret;
  126. }