Skip to content

Commit

Permalink
USB: gadgetfs race fix
Browse files Browse the repository at this point in the history
This resolves a race in gadgetfs associated with changing device/ep0
when processing control requests.  The fix is to change that state
earlier, when the control response is issued, so there's no window
in which userspace could see the wrong state; and enlarge the scope
of the spinlock during the ep0 request completion handler.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
David Brownell authored and Greg Kroah-Hartman committed Feb 7, 2007
1 parent 0864c7a commit 5b89db0
Showing 1 changed file with 11 additions and 7 deletions.
18 changes: 11 additions & 7 deletions drivers/usb/gadget/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,28 +933,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
{
struct dev_data *dev = ep->driver_data;
unsigned long flags;
int free = 1;

/* for control OUT, data must still get to userspace */
spin_lock_irqsave(&dev->lock, flags);
if (!dev->setup_in) {
dev->setup_out_error = (req->status != 0);
if (!dev->setup_out_error)
free = 0;
dev->setup_out_ready = 1;
ep0_readable (dev);
} else {
unsigned long flags;

spin_lock_irqsave(&dev->lock, flags);
if (dev->state == STATE_DEV_SETUP)
dev->state = STATE_DEV_CONNECTED;
spin_unlock_irqrestore(&dev->lock, flags);
}

/* clean up as appropriate */
if (free && req->buf != &dev->rbuf)
clean_req (ep, req);
req->complete = epio_complete;
spin_unlock_irqrestore(&dev->lock, flags);
}

static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
Expand Down Expand Up @@ -1036,6 +1032,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
spin_lock_irq (&dev->lock);
if (retval)
goto done;

if (dev->state != STATE_DEV_SETUP) {
retval = -ECANCELED;
goto done;
}
dev->state = STATE_DEV_CONNECTED;

if (dev->setup_out_error)
retval = -EIO;
else {
Expand Down Expand Up @@ -1187,6 +1190,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
if (dev->setup_in) {
retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) {
dev->state = STATE_DEV_CONNECTED;
spin_unlock_irq (&dev->lock);
if (copy_from_user (dev->req->buf, buf, len))
retval = -EFAULT;
Expand Down

0 comments on commit 5b89db0

Please sign in to comment.