[PATCH v2] Bluetooth: btintel_pcie: Fix DMA memory leak on probe failure

Zhao Dongdong posted 1 patch 1 week, 4 days ago
There is a newer version of this series
drivers/bluetooth/btintel_pcie.c | 6 ++++++
1 file changed, 6 insertions(+)
[PATCH v2] Bluetooth: btintel_pcie: Fix DMA memory leak on probe failure
Posted by Zhao Dongdong 1 week, 4 days ago
From: Zhao Dongdong <zhaodongdong@kylinos.cn>

In btintel_pcie_probe(), when btintel_pcie_alloc() succeeds but a
later step (btintel_pcie_enable_bt, btintel_pcie_start_rx, or
btintel_pcie_setup_hdev) fails, the DMA buffers and descriptors
allocated by btintel_pcie_alloc() are not freed. The exit_error
path only resets the device and destroys workqueues, causing a
DMA memory leak.

Fix this by calling btintel_pcie_free(data) after btintel_pcie_reset_bt()
to release all DMA buffers and the DMA pool. A NULL guard is added
in btintel_pcie_free() and data->dma_pool is cleared after any
partial allocation failure in btintel_pcie_alloc(), making the
unconditional free() call safe on all error paths.

Fixes: c2b636b3f788 ("Bluetooth: btintel_pcie: Add support for PCIe transport")
Signed-off-by: Zhao Dongdong <zhaodongdong@kylinos.cn>
---
v2: Fix UAF in probe error path by resetting hardware before freeing DMA.
v1: https://lore.kernel.org/linux-bluetooth/tencent_44ED865C14DA3D3823CA85AE1DF2CEBC1805@qq.com/
---
 drivers/bluetooth/btintel_pcie.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 9e39327dc1fe..a005b2e390a2 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -1920,6 +1920,9 @@ static int btintel_pcie_setup_rxq_bufs(struct btintel_pcie_data *data,
 
 static void btintel_pcie_free(struct btintel_pcie_data *data)
 {
+	if (!data->dma_pool)
+		return;
+
 	btintel_pcie_free_rxq_bufs(data, &data->rxq);
 	btintel_pcie_free_txq_bufs(data, &data->txq);
 
@@ -1980,6 +1983,7 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data)
 				 &p_addr);
 	if (!v_addr) {
 		dma_pool_destroy(data->dma_pool);
+		data->dma_pool = NULL;
 		err = -ENOMEM;
 		goto exit_error;
 	}
@@ -2072,6 +2076,7 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data)
 exit_error_pool:
 	dma_pool_free(data->dma_pool, data->dma_v_addr, data->dma_p_addr);
 	dma_pool_destroy(data->dma_pool);
+	data->dma_pool = NULL;
 exit_error:
 	return err;
 }
@@ -2918,6 +2923,7 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
 exit_error:
 	/* reset device before exit */
 	btintel_pcie_reset_bt(data);
+	btintel_pcie_free(data);
 
 	destroy_workqueue(data->coredump_workqueue);
 
-- 
2.25.1