diff options
author | Chao Bi <chao.bi@intel.com> | 2014-04-14 11:19:53 +0800 |
---|---|---|
committer | Marek Szyprowski <m.szyprowski@samsung.com> | 2014-06-11 11:02:22 +0200 |
commit | 9b6f0028f4029738130458e9103b54957116b768 (patch) | |
tree | 2436c8aa8a8fd9527e41cbad1b162e6baa51007e | |
parent | 5884c2412d484d87b30cab6a6493bb43c83d8288 (diff) | |
download | linux-3.10-9b6f0028f4029738130458e9103b54957116b768.tar.gz linux-3.10-9b6f0028f4029738130458e9103b54957116b768.tar.bz2 linux-3.10-9b6f0028f4029738130458e9103b54957116b768.zip |
usb: gadget: ffs: race between ffs_epfile_io() and ffs_func_eps_disable()
ffs_epfile_io() is called from userspace, while ffs_func_eps_disable() might be
called from USB disconnect interrupt, the two functions would run in parallel
but they are not well protected, that epfile->ep would be removed by
ffs_func_eps_disable() during ffs_epfile_io() is referring this pointer, then
it leads to kernel PANIC.
The scenario is as below:
Thread 1 Thread 2
| |
SyS_read dwc3_gadget_disconnect_interrupt
| |
ffs_epfile_read reset_config
| |
ffs_epfile_io ffs_func_eps_disable
| |
----- usb_ep_disable(): epfile->ep->ep->desc = NULL
| |
usb_ep_align_maybe(): -----
it refers ep->desc->wMaxPacketSize -----
Signed-off-by: Chao Bi <chao.bi@intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
[backport from upstream commit 97839ca4b06ab27790700ad7da6be9a75fc0cc1d]
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Change-id: I97839ca4b06ab27790700ad7da6be9a75fc0cc1d
-rw-r--r-- | drivers/usb/gadget/f_fs.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 5daf173c335..20b372b5909 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -745,6 +745,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) */ struct usb_gadget *gadget = epfile->ffs->gadget; + spin_lock_irq(&epfile->ffs->eps_lock); + /* In the meantime, endpoint got disabled or changed. */ + if (epfile->ep != ep) { + spin_unlock_irq(&epfile->ffs->eps_lock); + return -ESHUTDOWN; + } /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. @@ -752,6 +758,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) data_len = io_data->read ? usb_ep_align_maybe(gadget, ep->ep, io_data->len) : io_data->len; + spin_unlock_irq(&epfile->ffs->eps_lock); data = kmalloc(data_len, GFP_KERNEL); if (unlikely(!data)) |