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

Commit 44f86b53 authored by Sujeet Kumar's avatar Sujeet Kumar
Browse files

USB: f_fs: Move ep completion out of stack



Allocating completion on the stack may lead to
invalid access when udc irq tries to complete
the request but interrupted completion returns
immediately. This happens because request is not
held to be dequeued anymore making the completion
invalid.

Move the completions in ffs data like it is for ep0.

CRs-Fixed: 653761
Change-Id: I15102538d1b5bee14dfa3c7b3fa1f8e3f767cf71
Signed-off-by: default avatarSujeet Kumar <ksujeet@codeaurora.org>
parent 3fd4f55f
Loading
Loading
Loading
Loading
+18 −4
Original line number Diff line number Diff line
@@ -141,6 +141,8 @@ struct ffs_data {
	struct usb_request		*ep0req;		/* P: mutex */
	struct completion		ep0req_completion;	/* P: mutex */
	int				ep0req_status;		/* P: mutex */
	struct completion		epin_completion;
	struct completion		epout_completion;

	/* reference counter */
	atomic_t			ref;
@@ -749,8 +751,11 @@ static const struct file_operations ffs_ep0_operations = {

static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{
	struct ffs_ep *ep = _ep->driver_data;
	ENTER();
	if (likely(req->context)) {

	/* req may be freed during unbind */
	if (ep && ep->req && likely(req->context)) {
		struct ffs_ep *ep = _ep->driver_data;
		ep->status = req->status ? req->status : req->actual;
		complete(req->context);
@@ -762,6 +767,7 @@ static ssize_t ffs_epfile_io(struct file *file,
{
	struct ffs_epfile *epfile = file->private_data;
	struct ffs_ep *ep;
	struct ffs_data *ffs = epfile->ffs;
	char *data = NULL;
	ssize_t ret;
	int halt;
@@ -863,21 +869,27 @@ first_try:
		ret = -EBADMSG;
	} else {
		/* Fire the request */
		DECLARE_COMPLETION_ONSTACK(done);
		struct completion *done;

		struct usb_request *req = ep->req;
		req->context  = &done;
		req->complete = ffs_epfile_io_complete;
		req->buf      = data;
		req->length   = buffer_len;

		if (read) {
			INIT_COMPLETION(ffs->epout_completion);
			req->context  = done = &ffs->epout_completion;
		} else {
			INIT_COMPLETION(ffs->epin_completion);
			req->context  = done = &ffs->epin_completion;
		}
		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);

		spin_unlock_irq(&epfile->ffs->eps_lock);

		if (unlikely(ret < 0)) {
			ret = -EIO;
		} else if (unlikely(wait_for_completion_interruptible(&done))) {
		} else if (unlikely(wait_for_completion_interruptible(done))) {
			spin_lock_irq(&epfile->ffs->eps_lock);
			/*
			 * While we were acquiring lock endpoint got disabled
@@ -1369,6 +1381,8 @@ static struct ffs_data *ffs_data_new(void)
	spin_lock_init(&ffs->eps_lock);
	init_waitqueue_head(&ffs->ev.waitq);
	init_completion(&ffs->ep0req_completion);
	init_completion(&ffs->epout_completion);
	init_completion(&ffs->epin_completion);

	/* XXX REVISIT need to update it in some places, or do we? */
	ffs->ev.can_stall = 1;