USB: f_fs: Fix disconnect check during ongoing IO
F_FS function driver allocated ffs_eps and updates ffs_ep->ep to corresponding usb_ep during func->bind and never clears it. On bind it also saves ffs_ep context in epfile->ep. During func->disable, it clears only ffs_ep context in epfile->ep and on func->unbind it frees ffs_eps memory. ffs_epfile_io routine currently relies on ffs_ep->ep (which is never cleared and ffs_ep could be freed on unbind) to detect any disconnect during active IO. This can result in various issues e.g. use after free use of ffs_ep if unbind finished before epfile_io could resume or "stop adbd" trying to dequeue a freed USB request when epfile_io could execute only after F_FS got disabled as 'if (ep->ep)' check would be TRUE. Fix this by checking stored ffs_ep context against latest epfile->ep to figure out if endpoint got disabled or changed before acquiring spin_lock. Change-Id: I6bdcdf0dff0813ed7b2af8c24f544a22796b0369 Signed-off-by: Manu Gautam <mgautam@codeaurora.org> Signed-off-by: Mayank Rana <mrana@codeaurora.org>
This commit is contained in:
parent
e822c0fcf5
commit
f5ae88ff36
1 changed files with 13 additions and 2 deletions
|
@ -848,7 +848,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
|||
} else if (unlikely(
|
||||
wait_for_completion_interruptible(&done))) {
|
||||
spin_lock_irq(&epfile->ffs->eps_lock);
|
||||
if (ep->ep)
|
||||
/*
|
||||
* While we were acquiring lock endpoint got
|
||||
* disabled (disconnect) or changed
|
||||
* (composition switch) ?
|
||||
*/
|
||||
if (epfile->ep == ep)
|
||||
usb_ep_dequeue(ep->ep, req);
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
ret = -EINTR;
|
||||
|
@ -861,7 +866,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
|||
* data then user space has space for.
|
||||
*/
|
||||
spin_lock_irq(&epfile->ffs->eps_lock);
|
||||
if (ep->ep)
|
||||
/*
|
||||
* While we were acquiring lock endpoint got
|
||||
* disabled (disconnect) or changed
|
||||
* (composition switch) ?
|
||||
*/
|
||||
if (epfile->ep == ep)
|
||||
ret = ep->status;
|
||||
else
|
||||
ret = -ENODEV;
|
||||
|
@ -3268,6 +3278,7 @@ static void ffs_func_unbind(struct usb_configuration *c,
|
|||
if (ep->ep && ep->req)
|
||||
usb_ep_free_request(ep->ep, ep->req);
|
||||
ep->req = NULL;
|
||||
ep->ep = NULL;
|
||||
++ep;
|
||||
} while (--count);
|
||||
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
|
||||
|
|
Loading…
Add table
Reference in a new issue