From ae31bcc92bb42502bb7c9029e6dc7a824cf6cd14 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Mon, 27 Jul 2026 18:38:49 +0800 Subject: [PATCH 1/5] mmc: sdhci: make tuning_err a signed int Coverity report INTEGER_OVERFLOW for host->tuning_err. The tuning_err field in struct sdhci_host is used to store an error code for re-tuning, but it was declared as unsigned int. Several call sites store negative error codes into it and later compare against negative values: - sdhci.c, sdhci-of-dwcmshc.c and sdhci-pci-gli.c assign it the return value of __sdhci_execute_tuning()/__sdhci_execute_tuning_9750(), both of which return a signed int (possibly a negative errno); - sdhci-of-esdhc.c assigns host->tuning_err = -EAGAIN and later does "ret = host->tuning_err; if (ret == -EAGAIN ...)"; - sdhci-of-dwcmshc.c prints it with the %d (signed) conversion. Storing a negative errno in an unsigned int and reading it back as a signed int only happens to work because of two's-complement, same-width integer conversions. It is misleading and triggers sign-conversion warnings. All users treat the value either as a signed error code or as a boolean (zero / non-zero), so changing the type to a signed int is safe and makes the intent explicit. Fixes: 7d8bb1f46e13 ("mmc: sdhci: add tuning error codes") Assisted-by: Cline:claude-sonnet [read_file, search_files, git] Signed-off-by: Haibo Chen Reviewed-by: Frank Li Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index b6a571d866fa..f0fd81409a86 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -659,7 +659,7 @@ struct sdhci_host { unsigned int tuning_count; /* Timer count for re-tuning */ unsigned int tuning_mode; /* Re-tuning mode supported by host */ - unsigned int tuning_err; /* Error code for re-tuning */ + int tuning_err; /* Error code for re-tuning */ #define SDHCI_TUNING_MODE_1 0 #define SDHCI_TUNING_MODE_2 1 #define SDHCI_TUNING_MODE_3 2 From 9e9f561269dff35e6f84ed21776ec37fd6360b03 Mon Sep 17 00:00:00 2001 From: Myeonghun Pak Date: Mon, 27 Jul 2026 23:03:22 +0900 Subject: [PATCH 2/5] mmc: sdhci: unmap the bounce buffer before device release sdhci_allocate_bounce_buffer() allocates its buffer with devm_kmalloc() but maps it with dma_map_single(). The buffer is therefore released by devres without the streaming DMA mapping being unmapped. Register a managed action after dma_map_single() succeeds so the mapping is removed before devres releases the buffer. The action is registered only for buffers allocated and mapped by the SDHCI core, leaving buffers provided by host drivers under their existing ownership. Fixes: bd9b902798ab ("mmc: sdhci: Implement an SDHCI-specific bounce buffer") Cc: stable@vger.kernel.org Co-developed-by: Ijae Kim Signed-off-by: Ijae Kim Signed-off-by: Myeonghun Pak Reviewed-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index e3bf901b10aa..efb4c7742fe2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -4187,6 +4187,14 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver, } EXPORT_SYMBOL_GPL(__sdhci_read_caps); +static void sdhci_unmap_bounce_buffer(void *data) +{ + struct sdhci_host *host = data; + + dma_unmap_single(mmc_dev(host->mmc), host->bounce_addr, + host->bounce_buffer_size, DMA_BIDIRECTIONAL); +} + static void sdhci_allocate_bounce_buffer(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; @@ -4247,6 +4255,14 @@ static void sdhci_allocate_bounce_buffer(struct sdhci_host *host) } host->bounce_buffer_size = bounce_size; + ret = devm_add_action_or_reset(mmc_dev(mmc), + sdhci_unmap_bounce_buffer, host); + if (ret) { + devm_kfree(mmc_dev(mmc), host->bounce_buffer); + host->bounce_buffer = NULL; + host->bounce_buffer_size = 0; + return; + } out: /* Lie about this since we're bouncing */ From c125ee35a49a0518521b52b27631eef061b8719a Mon Sep 17 00:00:00 2001 From: Pei Xiao Date: Mon, 3 Aug 2026 17:48:21 +0800 Subject: [PATCH 3/5] mmc: atmel-mci: Fix use-after-free in atmci_remove due to race condition In atmci_probe, &host->bh_work is bound with atmci_work_func, and atmci_interrupt, atmci_timeout_timer and atmci_dma_complete can all queue this work on system_bh_wq. If we remove the module, atmci_remove makes cleanup and the memory allocated for host with devm_kzalloc() 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 | atmci_interrupt | queue_work(system_bh_wq, | &host->bh_work) atmci_remove | atmci_cleanup_slot(...) | atmci_writel(host, ATMCI_IDR, ~0UL) | timer_delete_sync(&host->timer) | dma_release_channel(host->dma.chan) | free_irq(platform_get_irq(pdev, 0), host) | | atmci_work_func | // use host // devm resources released after | // remove returns, host is freed | | // use host (use-after-free) Fix it by canceling the work after all the sources that can schedule it (IRQ handler, timeout timer and DMA completion callback) have been stopped, and before proceeding with the remaining cleanup in atmci_remove. Fixes: 7d2be0749a59 ("atmel-mci: Driver for Atmel on-chip MMC controllers") Assisted-by: Codex:deepseek-v4-flash Signed-off-by: Pei Xiao Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 3b4928f5b9b2..8f4df250a77a 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2610,6 +2610,8 @@ static void atmci_remove(struct platform_device *pdev) free_irq(platform_get_irq(pdev, 0), host); + cancel_work_sync(&host->bh_work); + clk_disable_unprepare(host->mck); pm_runtime_disable(dev); From f64ea900e4bda3055ef24a2c906f8d049cf1c3bd Mon Sep 17 00:00:00 2001 From: Zhan Xusheng Date: Tue, 4 Aug 2026 10:25:00 +0800 Subject: [PATCH 4/5] mmc: omap_hsmmc: fix busy_timeout overflow in ns conversion on 32-bit omap_hsmmc_prepare_data() converts the command busy timeout to nanoseconds with: timeout = req->cmd->busy_timeout * NSEC_PER_MSEC; busy_timeout is an unsigned int (milliseconds) and timeout is a u64, but NSEC_PER_MSEC is 1000000L. On 32-bit builds the multiplication is performed in 32-bit arithmetic and wraps for busy_timeout values above ~4294 ms, before the result is assigned to the u64. The driver does not set mmc->max_busy_timeout, so the core does not cap the busy timeout, and commands such as erase or SANITIZE (MMC_SANITIZE_TIMEOUT_MS is 240000 ms) can pass a busy_timeout far larger than 4294 ms. The wrapped, much smaller ns value is then programmed via set_data_timeout(), so the data timeout is set too short and the operation can time out prematurely. Cast busy_timeout to u64 before the multiplication so the conversion is done in 64-bit arithmetic. Fixes: 8cc9a3e73de1 ("mmc: host: omap_hsmmc: use generic_cmd6_time to program timeout value for CMD6") Cc: stable@vger.kernel.org Signed-off-by: Zhan Xusheng Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 58c881f2725b..3356ac5a1fa0 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1357,7 +1357,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) if (req->data == NULL) { OMAP_HSMMC_WRITE(host->base, BLK, 0); if (req->cmd->flags & MMC_RSP_BUSY) { - timeout = req->cmd->busy_timeout * NSEC_PER_MSEC; + timeout = (u64)req->cmd->busy_timeout * NSEC_PER_MSEC; /* * Set an arbitrary 100ms data timeout for commands with From 00179ed9fbe07799676e2cb63c4e7f0e7cd80a5c Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Tue, 4 Aug 2026 14:12:00 +0800 Subject: [PATCH 5/5] mmc: loongson2: Fix sg iteration in data reorder functions In ls2k0500_mmc_reorder_cmd_data() and ls2k2000_mmc_reorder_cmd_data(), the for_each_sg() macro already iterates over the scatterlist entries, with 'sg' pointing to the current entry. However, the code incorrectly uses '&sg[i]' and 'sg_dma_len(&sg[i])' inside the loop, which treats 'sg' as an array base and indexes it again, leading to access of wrong sg entries (or out-of-bounds if the list is not an array). Cc: stable@vger.kernel.org Fixes: d0f8e961deae ("mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver") Fixes: 2115772014bd ("mmc: loongson2: Add Loongson-2K SD/SDIO controller driver") Signed-off-by: Binbin Zhou Signed-off-by: Ulf Hansson --- drivers/mmc/host/loongson2-mmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/loongson2-mmc.c b/drivers/mmc/host/loongson2-mmc.c index f553e92fd9e5..118eccbaf8cd 100644 --- a/drivers/mmc/host/loongson2-mmc.c +++ b/drivers/mmc/host/loongson2-mmc.c @@ -641,8 +641,8 @@ static void ls2k0500_mmc_reorder_cmd_data(struct loongson2_mmc_host *host, return; for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) { - data = sg_virt(&sg[i]); - for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++) + data = sg_virt(sg); + for (j = 0; j < (sg_dma_len(sg) / 4); j++) if (cmd->opcode == SD_SWITCH) data[j] = bitrev8x4(data[j]); else @@ -758,8 +758,8 @@ static void ls2k2000_mmc_reorder_cmd_data(struct loongson2_mmc_host *host, return; for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) { - data = sg_virt(&sg[i]); - for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++) + data = sg_virt(sg); + for (j = 0; j < (sg_dma_len(sg) / 4); j++) data[j] = bitrev8x4(data[j]); } }