[PATCH] mmc: hsq: Fix use-after-free in retry work

Fan Wu posted 1 patch 1 month, 2 weeks ago
drivers/mmc/host/mmc_hsq.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
[PATCH] mmc: hsq: Fix use-after-free in retry work
Posted by Fan Wu 1 month, 2 weeks ago
mmc_hsq_pump_requests() queues retry_work when request_atomic() returns
-EBUSY; today sdhci-sprd is the only consumer that implements
request_atomic(). The work is embedded in a devm-allocated mmc_hsq, but
is never cancelled during driver removal. Work still pending at unbind
can therefore run after the devm allocation has been released and
dereference hsq->mmc and hsq->mrq.

Use devm_work_autocancel() to cancel and drain retry_work before the devm
allocation is released. By the time devres cleanup begins,
mmc_remove_host() has already stopped the host, so no new requests can
arm the work.

This issue was found by an in-house static analysis tool.

Fixes: 6db96e5810e0 ("mmc: host: Introduce the request_atomic() for the host")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
---
 drivers/mmc/host/mmc_hsq.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c
index 79836705c..57e172bd3 100644
--- a/drivers/mmc/host/mmc_hsq.c
+++ b/drivers/mmc/host/mmc_hsq.c
@@ -7,6 +7,7 @@
  * Author: Baolin Wang <baolin.wang@linaro.org>
  */
 
+#include <linux/devm-helpers.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/module.h>
@@ -345,6 +346,7 @@ static const struct mmc_cqe_ops mmc_hsq_ops = {
 
 int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
 {
+	int ret;
 	int i;
 	hsq->num_slots = HSQ_NUM_SLOTS;
 	hsq->next_tag = HSQ_INVALID_TAG;
@@ -363,7 +365,11 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
 	for (i = 0; i < HSQ_NUM_SLOTS; i++)
 		hsq->tag_slot[i] = HSQ_INVALID_TAG;
 
-	INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler);
+	ret = devm_work_autocancel(mmc_dev(mmc), &hsq->retry_work,
+				   mmc_hsq_retry_handler);
+	if (ret)
+		return ret;
+
 	spin_lock_init(&hsq->lock);
 	init_waitqueue_head(&hsq->wait_queue);
Re: [PATCH] mmc: hsq: Fix use-after-free in retry work
Posted by Ulf Hansson 3 weeks, 3 days ago
On Fri, Aug 14, 2026 at 10:23 AM Fan Wu <fanwu01@zju.edu.cn> wrote:
>
> mmc_hsq_pump_requests() queues retry_work when request_atomic() returns
> -EBUSY; today sdhci-sprd is the only consumer that implements
> request_atomic(). The work is embedded in a devm-allocated mmc_hsq, but
> is never cancelled during driver removal. Work still pending at unbind
> can therefore run after the devm allocation has been released and
> dereference hsq->mmc and hsq->mrq.
>
> Use devm_work_autocancel() to cancel and drain retry_work before the devm
> allocation is released. By the time devres cleanup begins,
> mmc_remove_host() has already stopped the host, so no new requests can
> arm the work.
>
> This issue was found by an in-house static analysis tool.
>
> Fixes: 6db96e5810e0 ("mmc: host: Introduce the request_atomic() for the host")
> Cc: stable@vger.kernel.org
> Assisted-by: Codex:gpt-5.6
> Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>

Applied for fixes, thanks!

Kind regards
Uffe


> ---
>  drivers/mmc/host/mmc_hsq.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c
> index 79836705c..57e172bd3 100644
> --- a/drivers/mmc/host/mmc_hsq.c
> +++ b/drivers/mmc/host/mmc_hsq.c
> @@ -7,6 +7,7 @@
>   * Author: Baolin Wang <baolin.wang@linaro.org>
>   */
>
> +#include <linux/devm-helpers.h>
>  #include <linux/mmc/card.h>
>  #include <linux/mmc/host.h>
>  #include <linux/module.h>
> @@ -345,6 +346,7 @@ static const struct mmc_cqe_ops mmc_hsq_ops = {
>
>  int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
>  {
> +       int ret;
>         int i;
>         hsq->num_slots = HSQ_NUM_SLOTS;
>         hsq->next_tag = HSQ_INVALID_TAG;
> @@ -363,7 +365,11 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
>         for (i = 0; i < HSQ_NUM_SLOTS; i++)
>                 hsq->tag_slot[i] = HSQ_INVALID_TAG;
>
> -       INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler);
> +       ret = devm_work_autocancel(mmc_dev(mmc), &hsq->retry_work,
> +                                  mmc_hsq_retry_handler);
> +       if (ret)
> +               return ret;
> +
>         spin_lock_init(&hsq->lock);
>         init_waitqueue_head(&hsq->wait_queue);