[PATCH] scsi: mvsas: fix tasklet use-after-free in mvs_pci_remove
From: Fan Wu
Date: Mon Aug 10 2026 - 22:56:24 EST
The tasklet is killed before the device IRQ is freed. The IRQ handler
schedules the tasklet, so an interrupt after tasklet_kill() can
reschedule it to run after its backing data has been freed, and the
tasklet re-enables the interrupt on exit. Move tasklet_kill() below
free_irq() and disable the interrupt again once it has drained.
This issue was found by an in-house static analysis tool.
Fixes: 6f8ac161b8b3 ("[SCSI] mvsas: Add support for interrupt tasklet")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@xxxxxxxxxx>
---
drivers/scsi/mvsas/mv_init.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -588,13 +588,14 @@ static void mvs_pci_remove(struct pci_dev *pdev)
core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
-#ifdef CONFIG_SCSI_MVSAS_TASKLET
- tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
-#endif
-
sas_unregister_ha(sha);
sas_remove_host(mvi->shost);
MVS_CHIP_DISP->interrupt_disable(mvi);
free_irq(mvi->pdev->irq, sha);
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+ /* drain after free_irq(): the tasklet re-enables the IRQ on exit */
+ tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
+ MVS_CHIP_DISP->interrupt_disable(mvi);
+#endif
for (i = 0; i < core_nr; i++) {
mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
mvs_free(mvi);
--
2.39.5