[PATCH] scsi: ipr: Fix use-after-free in __ipr_remove()
From: Fan Wu
Date: Sat Oct 03 2026 - 12:46:01 EST
__ipr_remove() flushes ioa_cfg->work_q and reset_work_q but never
drains scsi_add_work_q. Whenever scanning is enabled, ipr_worker_thread()
queues that work, so ipr_add_remove_thread() can still be pending or
running while __ipr_remove() proceeds to ipr_free_all_resources(), which
drops the last reference to the SCSI host via scsi_host_put() and frees
ioa_cfg. ipr_add_remove_thread() then dereferences the freed ioa_cfg,
including ioa_cfg->host->host_lock and ioa_cfg->used_res_q.
Fix this by cancelling scsi_add_work_q with cancel_work_sync() after the
existing flushes and before any resource is freed. ipr_worker_thread() is
the only scheduler of this work and reset completion can re-queue work_q,
so both flushes must precede the cancel.
The cancel is safe: ipr_add_remove_thread() never re-queues itself or
work_q, and __ipr_remove() holds no lock at that point.
This issue was found by an in-house static analysis tool.
Fixes: 318ddb34b205 ("scsi: ipr: System hung while dlpar adding primary ipr adapter back")
Cc: stable@xxxxxxxxxxxxxxx
Co-developed-by: Song Li <songl@xxxxxxxxxx>
Signed-off-by: Song Li <songl@xxxxxxxxxx>
Signed-off-by: Fan Wu <fanwu01@xxxxxxxxxx>
---
drivers/scsi/ipr.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index d207e5e..be2e46b 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -9700,6 +9700,7 @@ static void __ipr_remove(struct pci_dev *pdev)
flush_work(&ioa_cfg->work_q);
if (ioa_cfg->reset_work_q)
flush_workqueue(ioa_cfg->reset_work_q);
+ cancel_work_sync(&ioa_cfg->scsi_add_work_q);
INIT_LIST_HEAD(&ioa_cfg->used_res_q);
spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);