]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.1/usbnet-fix-kernel-crash-after-disconnect.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / queue-5.1 / usbnet-fix-kernel-crash-after-disconnect.patch
1 From foo@baz Fri 31 May 2019 03:16:39 PM PDT
2 From: Kloetzke Jan <Jan.Kloetzke@preh.de>
3 Date: Tue, 21 May 2019 13:18:40 +0000
4 Subject: usbnet: fix kernel crash after disconnect
5
6 From: Kloetzke Jan <Jan.Kloetzke@preh.de>
7
8 [ Upstream commit ad70411a978d1e6e97b1e341a7bde9a79af0c93d ]
9
10 When disconnecting cdc_ncm the kernel sporadically crashes shortly
11 after the disconnect:
12
13 [ 57.868812] Unable to handle kernel NULL pointer dereference at virtual address 00000000
14 ...
15 [ 58.006653] PC is at 0x0
16 [ 58.009202] LR is at call_timer_fn+0xec/0x1b4
17 [ 58.013567] pc : [<0000000000000000>] lr : [<ffffff80080f5130>] pstate: 00000145
18 [ 58.020976] sp : ffffff8008003da0
19 [ 58.024295] x29: ffffff8008003da0 x28: 0000000000000001
20 [ 58.029618] x27: 000000000000000a x26: 0000000000000100
21 [ 58.034941] x25: 0000000000000000 x24: ffffff8008003e68
22 [ 58.040263] x23: 0000000000000000 x22: 0000000000000000
23 [ 58.045587] x21: 0000000000000000 x20: ffffffc68fac1808
24 [ 58.050910] x19: 0000000000000100 x18: 0000000000000000
25 [ 58.056232] x17: 0000007f885aff8c x16: 0000007f883a9f10
26 [ 58.061556] x15: 0000000000000001 x14: 000000000000006e
27 [ 58.066878] x13: 0000000000000000 x12: 00000000000000ba
28 [ 58.072201] x11: ffffffc69ff1db30 x10: 0000000000000020
29 [ 58.077524] x9 : 8000100008001000 x8 : 0000000000000001
30 [ 58.082847] x7 : 0000000000000800 x6 : ffffff8008003e70
31 [ 58.088169] x5 : ffffffc69ff17a28 x4 : 00000000ffff138b
32 [ 58.093492] x3 : 0000000000000000 x2 : 0000000000000000
33 [ 58.098814] x1 : 0000000000000000 x0 : 0000000000000000
34 ...
35 [ 58.205800] [< (null)>] (null)
36 [ 58.210521] [<ffffff80080f5298>] expire_timers+0xa0/0x14c
37 [ 58.215937] [<ffffff80080f542c>] run_timer_softirq+0xe8/0x128
38 [ 58.221702] [<ffffff8008081120>] __do_softirq+0x298/0x348
39 [ 58.227118] [<ffffff80080a6304>] irq_exit+0x74/0xbc
40 [ 58.232009] [<ffffff80080e17dc>] __handle_domain_irq+0x78/0xac
41 [ 58.237857] [<ffffff8008080cf4>] gic_handle_irq+0x80/0xac
42 ...
43
44 The crash happens roughly 125..130ms after the disconnect. This
45 correlates with the 'delay' timer that is started on certain USB tx/rx
46 errors in the URB completion handler.
47
48 The problem is a race of usbnet_stop() with usbnet_start_xmit(). In
49 usbnet_stop() we call usbnet_terminate_urbs() to cancel all URBs in
50 flight. This only makes sense if no new URBs are submitted
51 concurrently, though. But the usbnet_start_xmit() can run at the same
52 time on another CPU which almost unconditionally submits an URB. The
53 error callback of the new URB will then schedule the timer after it was
54 already stopped.
55
56 The fix adds a check if the tx queue is stopped after the tx list lock
57 has been taken. This should reliably prevent the submission of new URBs
58 while usbnet_terminate_urbs() does its job. The same thing is done on
59 the rx side even though it might be safe due to other flags that are
60 checked there.
61
62 Signed-off-by: Jan Klötzke <Jan.Kloetzke@preh.de>
63 Signed-off-by: David S. Miller <davem@davemloft.net>
64 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
65 ---
66 drivers/net/usb/usbnet.c | 6 ++++++
67 1 file changed, 6 insertions(+)
68
69 --- a/drivers/net/usb/usbnet.c
70 +++ b/drivers/net/usb/usbnet.c
71 @@ -506,6 +506,7 @@ static int rx_submit (struct usbnet *dev
72
73 if (netif_running (dev->net) &&
74 netif_device_present (dev->net) &&
75 + test_bit(EVENT_DEV_OPEN, &dev->flags) &&
76 !test_bit (EVENT_RX_HALT, &dev->flags) &&
77 !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) {
78 switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
79 @@ -1431,6 +1432,11 @@ netdev_tx_t usbnet_start_xmit (struct sk
80 spin_unlock_irqrestore(&dev->txq.lock, flags);
81 goto drop;
82 }
83 + if (netif_queue_stopped(net)) {
84 + usb_autopm_put_interface_async(dev->intf);
85 + spin_unlock_irqrestore(&dev->txq.lock, flags);
86 + goto drop;
87 + }
88
89 #ifdef CONFIG_PM
90 /* if this triggers the device is still a sleep */