Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49543322 authored by Manu Gautam's avatar Manu Gautam Committed by Sujeet Kumar
Browse files

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: default avatarManu Gautam <mgautam@codeaurora.org>
parent eddaea8d
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -879,13 +879,21 @@ first_try:
			ret = -EIO;
		} 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;
		} else {
			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;
@@ -1565,6 +1573,7 @@ static void ffs_func_free(struct ffs_function *func)
		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);