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

From: Dawei Feng

Date: Tue Jun 02 2026 - 06:09:42 EST


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@xxxxxxxxxxxxxxx
Signed-off-by: Zilin Guan <zilin@xxxxxxxxxx>
Signed-off-by: Dawei Feng <dawei.feng@xxxxxxxxxx>
---
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