[PATCH] scsi: qla2xxx: Fix memory leak in qla2x00_mem_alloc()

Dawei Feng posted 1 patch 5 days, 16 hours ago
drivers/scsi/qla2xxx/qla_os.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
[PATCH] scsi: qla2xxx: Fix memory leak in qla2x00_mem_alloc()
Posted by Dawei Feng 5 days, 16 hours ago
In qla2x00_mem_alloc(), if kzalloc_obj() fails during the DIF bundling
buffer pool setup, the code directly returns -ENOMEM. This bypasses the
error unwind path and leaks previously allocated resources.

Fix this memory leak by routing the allocation failure to the
fail_dma_pool label.

The bug was first flagged by an experimental analysis tool we are
developing for kernel memory-management bugs while analyzing
v6.13-rc1. The tool is still under development and is not yet publicly
available. Manual inspection confirms that the bug is still
present in v7.1-rc6.

An x86_64 allyesconfig build showed no new warnings. As we do not have a
QLogic qla2xxx adapter configured to exercise the target-mode DIF setup
path, no runtime testing was able to be performed.

Fixes: 50b812755e97 ("scsi: qla2xxx: Fix DMA error when the DIF sg buffer crosses 4GB boundary")
Cc: stable@vger.kernel.org
Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
---
 drivers/scsi/qla2xxx/qla_os.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 72b1c28e4dae..8ebd2d0f06d6 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -4251,7 +4251,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 					ql_dbg_pci(ql_dbg_init, ha->pdev,
 					    0xe0ee, "%s: failed alloc dsd\n",
 					    __func__);
-					return -ENOMEM;
+					goto fail_dma_pool;
 				}
 				ha->dif_bundle_kallocs++;
 
@@ -4536,6 +4536,14 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	if (ql2xenabledif) {
 		struct dsd_dma *dsd, *nxt;
 
+		list_for_each_entry_safe(dsd, nxt, &ha->pool.good.head, list) {
+			list_del(&dsd->list);
+			dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, dsd->dsd_list_dma);
+			ha->dif_bundle_dma_allocs--;
+			kfree(dsd);
+			ha->dif_bundle_kallocs--;
+		}
+
 		list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head,
 		    list) {
 			list_del(&dsd->list);
-- 
2.34.1