mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
USB: gadget: inode: fix mm lifetime handling
priv stores a pointer to the submitting task's mm_struct, but does not currently hold a reference to it while async requests are pending. This can result in a use-after-free if the task exits before completion handling finishes. Take a reference with mmgrab() when queuing the read request and release it with mmdrop() on request completion. Reported-by: Gabriel Prostitis <prostitisgabriel@gmail.com> Signed-off-by: Gabriel Prostitis <prostitisgabriel@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Link: https://patch.msgid.link/20260601-mm-uaf-fix-v2-2-3c942a707bce@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
5eb5c72c72
commit
a1c33c80e1
|
|
@ -471,11 +471,17 @@ static void ep_user_copy_worker(struct work_struct *work)
|
|||
struct kiocb *iocb = priv->iocb;
|
||||
size_t ret;
|
||||
|
||||
kthread_use_mm(mm);
|
||||
ret = copy_to_iter(priv->buf, priv->actual, &priv->to);
|
||||
kthread_unuse_mm(mm);
|
||||
if (!ret)
|
||||
if (mmget_not_zero(mm)) {
|
||||
kthread_use_mm(mm);
|
||||
ret = copy_to_iter(priv->buf, priv->actual, &priv->to);
|
||||
kthread_unuse_mm(mm);
|
||||
mmput(mm);
|
||||
if (!ret)
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
ret = -EFAULT;
|
||||
}
|
||||
mmdrop(mm);
|
||||
|
||||
/* completing the iocb can drop the ctx and mm, don't touch mm after */
|
||||
iocb->ki_complete(iocb, ret);
|
||||
|
|
@ -501,6 +507,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
* complete the aio request immediately.
|
||||
*/
|
||||
if (priv->to_free == NULL || unlikely(req->actual == 0)) {
|
||||
mmdrop(priv->mm);
|
||||
kfree(req->buf);
|
||||
kfree(priv->to_free);
|
||||
kfree(priv);
|
||||
|
|
@ -541,6 +548,7 @@ static ssize_t ep_aio(struct kiocb *iocb,
|
|||
priv->epdata = epdata;
|
||||
priv->actual = 0;
|
||||
priv->mm = current->mm; /* mm teardown waits for iocbs in exit_aio() */
|
||||
mmgrab(priv->mm);
|
||||
|
||||
/* each kiocb is coupled to one usb_request, but we can't
|
||||
* allocate or submit those if the host disconnected.
|
||||
|
|
@ -570,6 +578,7 @@ static ssize_t ep_aio(struct kiocb *iocb,
|
|||
|
||||
fail:
|
||||
spin_unlock_irq(&epdata->dev->lock);
|
||||
mmdrop(priv->mm);
|
||||
kfree(priv->to_free);
|
||||
kfree(priv);
|
||||
put_ep(epdata);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user