[PATCH] mmc: via-sdmmc: Fix use-after-free in via_sd_remove due to race condition

Pei Xiao <[email protected]> Tue, 4 Aug 2026 09:40:15 +0800
Newsgroups org.kernel.vger.linux-mmc,org.kernel.vger.linux-kernel
Message-ID <94dac731cadea4732725a83bbbe1d8fe47636694.1785807411.git.xiaopei01@kylinos.cn>
In via_init_mmc_host, &sdhost->carddet_work is bound with
via_sdc_card_detect, and via_sdc_isr can schedule this work on
system_wq when it handles a card insertion/removal interrupt.

If we remove the device, via_sd_remove makes cleanup and the memory
allocated for sdhost with devm_mmc_alloc_host() is released after the
remove callback returns, while the work mentioned above may still be
pending or running. The sequence of operations that may lead to a UAF
bug is as follows:

CPU0                                      CPU1

                                          | via_sdc_isr
                                          | schedule_work(&sdhost->carddet_work)
via_sd_remove                             |
mmc_remove_host(sdhost->mmc)              |
free_irq(pcidev->irq, sdhost)             |
timer_delete_sync(&sdhost->timer)         |
cancel_work_sync(&sdhost->finish_bh_work) |
                                          | via_sdc_card_detect
                                          | // use sdhost
// devm resources released after          |
// remove returns, sdhost is freed        |
                                          | // use sdhost (use-after-free)

Fix it by canceling the work after the IRQ handler that can schedule
it has been stopped, and before proceeding with the remaining cleanup
in via_sd_remove.

Fixes: f0bf7f61b840 ("mmc: Add new via-sdmmc host controller driver")
Assisted-by: Codex:deepseek-v4-flash
Signed-off-by: Pei Xiao <[email protected]>
---
 drivers/mmc/host/via-sdmmc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 8c049f8355cd..be90fc767c74 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -1199,6 +1199,8 @@ static void via_sd_remove(struct pci_dev *pcidev)
 
 	free_irq(pcidev->irq, sdhost);
 
+	cancel_work_sync(&sdhost->carddet_work);
+
 	timer_delete_sync(&sdhost->timer);
 
 	cancel_work_sync(&sdhost->finish_bh_work);
-- 
2.25.1