Re: [PATCH v5] mmc: vub300: fix use-after-free on probe failure
Ulf Hansson <[email protected]> Mon, 6 Jul 2026 17:46:38 +0200
| Newsgroups | org.kernel.vger.linux-mmc,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAPx+jO8=L-_h9FET+Zp34j9OY24cmfX8jT=PV83_z0VtWssCZQ@mail.gmail.com> |
On Fri, Jun 12, 2026 at 5:28 AM Guangshuo Li <[email protected]> wrote: > > The vub300 driver lifetime-manages its controller state using > vub300->kref, with vub300_delete() freeing the mmc host when the last > reference is dropped. The probe error path after the inactivity timer has > been armed still bypasses that lifetime rule, however, and falls through > to mmc_free_host() directly if mmc_add_host() fails. > > The race window is between arming the inactivity timer and reaching the > probe error unwind after mmc_add_host() fails: > > probe thread timer/workqueue > ------------ --------------- > kref_init(&vub300->kref) ref = 1 > kref_get(&vub300->kref) ref = 2, timer ref > add_timer(inactivity_timer) fires after one second > | > | race window > |<----------------------------------------------------> > | > mmc_add_host(mmc) > inactivity timer fires > vub300_queue_dead_work() > kref_get() ref = 3 > queue_work(deadwork) > mmc_add_host() fails > timer_delete_sync() > mmc_free_host(mmc) > frees vub300 > deadwork runs > use-after-free > > The inactivity timeout is one second, so this would require > mmc_add_host() to both fail and take more than one second to do so. This > is unlikely to happen in practice, but the error path is still wrong. > > timer_delete_sync() only waits for the timer callback itself. It does > not flush deadwork that the callback may already have queued. As a > result, queued deadwork can still hold a kref while the probe error path > directly frees the backing mmc host, including the vub300 storage. > > Fix this by using the same lifetime mechanism as disconnect. Clear > vub300->interface so that the timer callback and any queued deadwork > return early and drop their references, then drop the initial probe > reference and return without falling through to err_free_host. > > Fixes: 0613ad2401f8 ("mmc: vub300: fix return value check of mmc_add_host()") > Signed-off-by: Guangshuo Li <[email protected]> > Reviewed-by: Johan Hovold <[email protected]> Applied for fixes and by adding a stable tag, thanks! Kind regards Uffe > --- > v5: > - Correct the Fixes tag. > - Add Johan's Reviewed-by tag. > > v4: > - Fix the Fixes tag to point to the commit which added the > mmc_add_host() failure unwind. > - Add Johan's Reviewed-by tag. > > v3: > - Use the disconnect-style teardown by clearing vub300->interface. > - Drop only the initial probe reference and let timer/deadwork drop their > own references. > - Mention the one-second inactivity timeout in the commit message. > > v2: > - Rebase on current mainline. > - Correct the Fixes tag. > - Add blank lines around the early return. > - Reword the code comment. > > drivers/mmc/host/vub300.c | 10 +++++++--- > 1 file changed, 7 insertions(+), 3 deletions(-) > > diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c > index 6c3cb2f1c9d3..c1c21e95f5bf 100644 > --- a/drivers/mmc/host/vub300.c > +++ b/drivers/mmc/host/vub300.c > @@ -2336,12 +2336,16 @@ static int vub300_probe(struct usb_interface *interface, > interface_to_InterfaceNumber(interface)); > retval = mmc_add_host(mmc); > if (retval) > - goto err_delete_timer; > + goto err_stop_io; > > return 0; > > -err_delete_timer: > - timer_delete_sync(&vub300->inactivity_timer); > +err_stop_io: > + vub300->interface = NULL; > + kref_put(&vub300->kref, vub300_delete); > + > + return retval; > + > err_free_host: > mmc_free_host(mmc); > /* > -- > 2.43.0 >