Skip to contentSkip to conversation

mmc: vub300: fix use-after-free in vub300 teardown

PATCH New Adriano Cordova 1 participant 2 messages Sep 9

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH v3 1/2 mmc: vub300: fix use-after-free in vub300 teardown

The request-completion paths call the final kref_put() before mmc_request_done(). Dropping the last reference can free the host via vub300_delete() -> mmc_free_host(), and mmc_request_done() then reads the freed host.

Call mmc_request_done() before the final kref_put() so the host is still valid.

Fixes 88095e7b473a ("mmc: Add new VUB300 USB-to-SD/SDIO/MMC driver")
Assisted-by opencode: deepseek v4 flash

---
Changes since v1:
- Added Assisted-by tag
Changes since v2:
- Split patch into two logical patches
- Corrected the Fixes: tag

 drivers/mmc/host/vub300.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mmc/host/vub300.c +2 -2
index 2dae474dcd06..c87c54aa0e99 100644
@@ -1794,8 +1794,8 @@ static void vub300_cmndwork_thread(struct work_struct *work)
 			construct_request_response(vub300, cmd);
 			vub300->resp_len = 0;
 			mutex_unlock(&vub300->cmd_mutex);
-			kref_put(&vub300->kref, vub300_delete);
 			mmc_request_done(vub300->mmc, req);
+			kref_put(&vub300->kref, vub300_delete);
 			return;
 		}
 	}
@@ -1946,8 +1946,8 @@ static void vub300_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
 		    satisfy_request_from_offloaded_data(vub300, cmd)) {
 			cmd->error = 0;
 			mutex_unlock(&vub300->cmd_mutex);
-			kref_put(&vub300->kref, vub300_delete);
 			mmc_request_done(mmc, req);
+			kref_put(&vub300->kref, vub300_delete);
 			return;
 		} else {
 			vub300->cmd = cmd;
Signature · 1 line
2.51.0
#1 lore raw

PATCH v3 2/2 mmc: core: don't dereference parent when releasing host index

mmc_host_classdev_release() reads host->parent->of_node to decide whether to free the IDA slot, but mmc_alloc_host() does not guarantee that the parent outlives the host (only devm_mmc_alloc_host() does). So the vub300 driver can release its parent usb_device before the host, resulting in a use-after-free.

Put the alias decision in host->index_is_alias at allocation time, while the parent is still valid, and use it at release time.

Fixes 10252bae863d ("mmc: core: Don't allocate IDA for OF aliases")
Reported-by [email protected]
Assisted-by opencode: deepseek v4 flash

---
Changes since v1:
- Added Assisted-by tag
- put alias decision in host->index_is_alias
Changes since v2:
- Split patch into two logical patches
- Corrected the Fixes: tag

 drivers/mmc/core/host.c | 3 ++-
 include/linux/mmc/host.h | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/mmc/core/host.c +2 -1
index b7ce3137d452..542bb033c6da 100644
@@ -67,7 +67,7 @@ static void mmc_host_classdev_release(struct device *dev)
 {
 	struct mmc_host *host = cls_dev_to_mmc_host(dev);
 	wakeup_source_unregister(host->ws);
-	if (of_alias_get_id(host->parent->of_node, "mmc") < 0)
+	if (!host->index_is_alias)
 		ida_free(&mmc_host_ida, host->index);
 	kfree(host);
 }
@@ -538,6 +538,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 	}
 
 	host->index = index;
+	host->index_is_alias = (alias_id >= 0);
 
 	dev_set_name(&host->class_dev, "mmc%d", host->index);
 	host->ws = wakeup_source_register(NULL, dev_name(&host->class_dev));
include/linux/mmc/host.h +1 -0
index ba84f02c2a10..165d24104d3c 100644
@@ -356,6 +356,7 @@ struct mmc_host {
 	struct device		*parent;
 	struct device		class_dev;
 	int			index;
+	bool			index_is_alias;
 	const struct mmc_host_ops *ops;
 	struct mmc_pwrseq	*pwrseq;
 	unsigned int		f_min;
Signature · 1 line
2.51.0