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