]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.11.2/usb-hub-do-not-attempt-to-autosuspend-disconnected-devices.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.11.2 / usb-hub-do-not-attempt-to-autosuspend-disconnected-devices.patch
1 From f5cccf49428447dfbc9edb7a04bb8fc316269781 Mon Sep 17 00:00:00 2001
2 From: Guenter Roeck <linux@roeck-us.net>
3 Date: Mon, 20 Mar 2017 14:30:50 -0700
4 Subject: usb: hub: Do not attempt to autosuspend disconnected devices
5
6 From: Guenter Roeck <linux@roeck-us.net>
7
8 commit f5cccf49428447dfbc9edb7a04bb8fc316269781 upstream.
9
10 While running a bind/unbind stress test with the dwc3 usb driver on rk3399,
11 the following crash was observed.
12
13 Unable to handle kernel NULL pointer dereference at virtual address 00000218
14 pgd = ffffffc00165f000
15 [00000218] *pgd=000000000174f003, *pud=000000000174f003,
16 *pmd=0000000001750003, *pte=00e8000001751713
17 Internal error: Oops: 96000005 [#1] PREEMPT SMP
18 Modules linked in: uinput uvcvideo videobuf2_vmalloc cmac
19 ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat rfcomm
20 xt_mark fuse bridge stp llc zram btusb btrtl btbcm btintel bluetooth
21 ip6table_filter mwifiex_pcie mwifiex cfg80211 cdc_ether usbnet r8152 mii joydev
22 snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq snd_seq_device ppp_async
23 ppp_generic slhc tun
24 CPU: 1 PID: 29814 Comm: kworker/1:1 Not tainted 4.4.52 #507
25 Hardware name: Google Kevin (DT)
26 Workqueue: pm pm_runtime_work
27 task: ffffffc0ac540000 ti: ffffffc0af4d4000 task.ti: ffffffc0af4d4000
28 PC is at autosuspend_check+0x74/0x174
29 LR is at autosuspend_check+0x70/0x174
30 ...
31 Call trace:
32 [<ffffffc00080dcc0>] autosuspend_check+0x74/0x174
33 [<ffffffc000810500>] usb_runtime_idle+0x20/0x40
34 [<ffffffc000785ae0>] __rpm_callback+0x48/0x7c
35 [<ffffffc000786af0>] rpm_idle+0x1e8/0x498
36 [<ffffffc000787cdc>] pm_runtime_work+0x88/0xcc
37 [<ffffffc000249bb8>] process_one_work+0x390/0x6b8
38 [<ffffffc00024abcc>] worker_thread+0x480/0x610
39 [<ffffffc000251a80>] kthread+0x164/0x178
40 [<ffffffc0002045d0>] ret_from_fork+0x10/0x40
41
42 Source:
43
44 (gdb) l *0xffffffc00080dcc0
45 0xffffffc00080dcc0 is in autosuspend_check
46 (drivers/usb/core/driver.c:1778).
47 1773 /* We don't need to check interfaces that are
48 1774 * disabled for runtime PM. Either they are unbound
49 1775 * or else their drivers don't support autosuspend
50 1776 * and so they are permanently active.
51 1777 */
52 1778 if (intf->dev.power.disable_depth)
53 1779 continue;
54 1780 if (atomic_read(&intf->dev.power.usage_count) > 0)
55 1781 return -EBUSY;
56 1782 w |= intf->needs_remote_wakeup;
57
58 Code analysis shows that intf is set to NULL in usb_disable_device() prior
59 to setting actconfig to NULL. At the same time, usb_runtime_idle() does not
60 lock the usb device, and neither does any of the functions in the
61 traceback. This means that there is no protection against a race condition
62 where usb_disable_device() is removing dev->actconfig->interface[] pointers
63 while those are being accessed from autosuspend_check().
64
65 To solve the problem, synchronize and validate device state between
66 autosuspend_check() and usb_disconnect().
67
68 Acked-by: Alan Stern <stern@rowland.harvard.edu>
69 Signed-off-by: Guenter Roeck <linux@roeck-us.net>
70 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
71
72 ---
73 drivers/usb/core/driver.c | 3 +++
74 drivers/usb/core/hub.c | 6 ++++++
75 2 files changed, 9 insertions(+)
76
77 --- a/drivers/usb/core/driver.c
78 +++ b/drivers/usb/core/driver.c
79 @@ -1781,6 +1781,9 @@ static int autosuspend_check(struct usb_
80 int w, i;
81 struct usb_interface *intf;
82
83 + if (udev->state == USB_STATE_NOTATTACHED)
84 + return -ENODEV;
85 +
86 /* Fail if autosuspend is disabled, or any interfaces are in use, or
87 * any interface drivers require remote wakeup but it isn't available.
88 */
89 --- a/drivers/usb/core/hub.c
90 +++ b/drivers/usb/core/hub.c
91 @@ -2087,6 +2087,12 @@ void usb_disconnect(struct usb_device **
92 dev_info(&udev->dev, "USB disconnect, device number %d\n",
93 udev->devnum);
94
95 + /*
96 + * Ensure that the pm runtime code knows that the USB device
97 + * is in the process of being disconnected.
98 + */
99 + pm_runtime_barrier(&udev->dev);
100 +
101 usb_lock_device(udev);
102
103 hub_disconnect_children(udev);