mmc: vub300: fix use-after-free in vub300 teardown
Subsystems (2)
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.
---
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
@@ -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
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.
---
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
@@ -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
@@ -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