summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChao Bi <chao.bi@intel.com>2014-04-14 11:19:53 +0800
committerMarek Szyprowski <m.szyprowski@samsung.com>2014-06-11 11:02:22 +0200
commit9b6f0028f4029738130458e9103b54957116b768 (patch)
tree2436c8aa8a8fd9527e41cbad1b162e6baa51007e
parent5884c2412d484d87b30cab6a6493bb43c83d8288 (diff)
downloadlinux-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.c7
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))