Skip to contentSkip to conversation

Gadget: race between ffs_epfile_io() and ffs_func_eps_disable()

PATCH New Chao Bi 1 participant 1 message Apr 8, 2014 USB

lore
Share & tools
lore

Chao Bi

author
#0 lore raw

PATCH 1/1 Gadget: race between ffs_epfile_io() and ffs_func_eps_disable()

ffs_epfile_io() is called from userspace, while ffs_func_esp_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_esp_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
   |                                        |From 772c1c9ef451a9a84e48acf14ba613328920a2f4 Mon Sep 17 00:00:00 2001

From: channing <[email protected]>
Date: Wed, 2 Apr 2014 16:37:57 +0800
Subject: [PATCH] Gadget: race between ffs_epfile_io() and
ffs_func_eps_disable()

ffs_epfile_io() is called from userspace, while ffs_func_esp_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_esp_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        -----
---
 drivers/usb/gadget/f_fs.c |    7 +++++++
 1 file changed, 7 insertions(+)
drivers/usb/gadget/f_fs.c +7 -0
index 2e164dc..1e12b3e 100644
@@ -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))
Signature · 16 lines
1.7.9.5


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 <[email protected]>
---
 drivers/usb/gadget/f_fs.c |    7 +++++++
 1 file changed, 7 insertions(+)
drivers/usb/gadget/f_fs.c +7 -0
index 2e164dc..1e12b3e 100644
@@ -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))
Signature · 1 line
1.7.9.5