USB: gadgetfs race fix
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>
This commit is contained in:
parent
0864c7a928
commit
5b89db02a5
1 changed files with 11 additions and 7 deletions
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue