summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanilo Krummrich <danilokrummrich@gmail.com>2017-08-14 12:45:38 +0200
committerAmit Pundir <amit.pundir@linaro.org>2017-12-18 21:11:22 +0530
commit4f3780ee59dc16c62dc66ba3c37b506343771769 (patch)
treebc0ec0f2c5419e437db6726af32b43e904cb81d9
parent70d35ff9e833da9cea6bcb5879c265e3f441baf1 (diff)
ANDROID: usb: gadget: configfs: fix null ptr in android_disconnect
There's a race between usb_gadget_udc_stop() which is likely to set the gadget driver to NULL in the udc driver and this drivers gadget disconnect fn which likely checks for the gadget driver to a null ptr. It happens that unbind (doing set_gadget_data(NULL)) is called before the gadget driver is set to NULL and the udc driver calls disconnect fn which results in cdev being a null ptr. As a workaround we check cdev in android_disconnect() to prevent the following panic: Unable to handle kernel NULL pointer dereference at virtual address 000000a8 pgd = ffffff800940a000 [000000a8] *pgd=00000000be1fe003, *pud=00000000be1fe003, *pmd=0000000000000000 Internal error: Oops: 96000046 [#1] PREEMPT SMP CPU: 7 PID: 1134 Comm: kworker/u16:3 Tainted: G S 4.9.41-g75cd2a0231ea-dirty #4 Hardware name: HiKey960 (DT) Workqueue: events_power_efficient event_work task: ffffffc0b5f4f000 task.stack: ffffffc0b5b94000 PC is at android_disconnect+0x54/0xa4 LR is at android_disconnect+0x54/0xa4 pc : [<ffffff8008855938>] lr : [<ffffff8008855938>] pstate: 80000185 sp : ffffffc0b5b97bf0 x29: ffffffc0b5b97bf0 x28: 0000000000000003 x27: ffffffc0b5181c54 x26: ffffffc0b5181c68 x25: ffffff8008dc1000 x24: ffffffc0b5181d70 x23: ffffff8008dc18a0 x22: ffffffc0b5f5a018 x21: ffffffc0b5894ad8 x20: 0000000000000000 x19: ffffff8008ddaec8 x18: 0000000000000000 x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 x14: 00000000007c9ccd x13: 0000000000000000 x12: 0000000000000000 x11: 0000000000000001 x10: 0000000000000001 x9 : ffffff800930f1a8 x8 : ffffff800932a133 x7 : 0000000000000000 x6 : 0000000000000000 x5 : ffffffc0b5b97a50 x4 : ffffffc0be19f090 x3 : 0000000000000000 x2 : ffffff80091ca000 x1 : 000000000000002f x0 : 000000000000002f This happened on a hikey960 with the following backtrace: [<ffffff8008855938>] android_disconnect+0x54/0xa4 [<ffffff80089def38>] dwc3_disconnect_gadget.part.19+0x114.888119] [<ffffff80087f7d48>] dwc3_gadget_suspend+0x6c/0x70 [<ffffff80087ee674>] dwc3_suspend_device+0x58/0xa0 [<ffffff80087fb418>] dwc3_otg_work+0x214/0x474 [<ffffff80087fdc74>] event_work+0x3bc/0x5ac [<ffffff80080e5d88>] process_one_work+0x14c/0x43c [<ffffff80080e60d4>] worker_thread+0x5c/0x438 [<ffffff80080ece68>] kthread+0xec/0x100 [<ffffff8008083680>] ret_from_fork+0x10/0x50 dwc3_otg_work tries to handle a switch from host to device mode and therefore calls disconnect on the gadget driver. To reproduce the issue it is enaugh to enable tethering (rndis gadget), unplug and plug in again the usb connector which causes the change from device to host and back to device mode. Signed-off-by: Danilo Krummrich <danilokrummrich@gmail.com>
-rw-r--r--drivers/usb/gadget/configfs.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 5ef6a4a13bd3..bf2d0ce80c99 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -1522,6 +1522,18 @@ static void android_disconnect(struct usb_gadget *gadget)
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
+ /* FIXME: There's a race between usb_gadget_udc_stop() which is likely
+ * to set the gadget driver to NULL in the udc driver and this drivers
+ * gadget disconnect fn which likely checks for the gadget driver to
+ * be a null ptr. It happens that unbind (doing set_gadget_data(NULL))
+ * is called before the gadget driver is set to NULL and the udc driver
+ * calls disconnect fn which results in cdev being a null ptr.
+ */
+ if (cdev == NULL) {
+ WARN(1, "%s: gadget driver already disconnected\n", __func__);
+ return;
+ }
+
/* accessory HID support can be active while the
accessory function is not actually enabled,
so we need to inform it when we are disconnected.