]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.14.111/usb-f_fs-avoid-crash-due-to-out-of-scope-stack-ptr-a.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.14.111 / usb-f_fs-avoid-crash-due-to-out-of-scope-stack-ptr-a.patch
CommitLineData
04fd09d4
SL
1From 0ad9f236a6d4bac2c8c12cbd5710b18646d3eca4 Mon Sep 17 00:00:00 2001
2From: John Stultz <john.stultz@linaro.org>
3Date: Tue, 5 Feb 2019 10:24:40 -0800
4Subject: usb: f_fs: Avoid crash due to out-of-scope stack ptr access
5
6[ Upstream commit 54f64d5c983f939901dacc8cfc0983727c5c742e ]
7
8Since the 5.0 merge window opened, I've been seeing frequent
9crashes on suspend and reboot with the trace:
10
11[ 36.911170] Unable to handle kernel paging request at virtual address ffffff801153d660
12[ 36.912769] Unable to handle kernel paging request at virtual address ffffff800004b564
13...
14[ 36.950666] Call trace:
15[ 36.950670] queued_spin_lock_slowpath+0x1cc/0x2c8
16[ 36.950681] _raw_spin_lock_irqsave+0x64/0x78
17[ 36.950692] complete+0x28/0x70
18[ 36.950703] ffs_epfile_io_complete+0x3c/0x50
19[ 36.950713] usb_gadget_giveback_request+0x34/0x108
20[ 36.950721] dwc3_gadget_giveback+0x50/0x68
21[ 36.950723] dwc3_thread_interrupt+0x358/0x1488
22[ 36.950731] irq_thread_fn+0x30/0x88
23[ 36.950734] irq_thread+0x114/0x1b0
24[ 36.950739] kthread+0x104/0x130
25[ 36.950747] ret_from_fork+0x10/0x1c
26
27I isolated this down to in ffs_epfile_io():
28https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/gadget/function/f_fs.c#n1065
29
30Where the completion done is setup on the stack:
31 DECLARE_COMPLETION_ONSTACK(done);
32
33Then later we setup a request and queue it, and wait for it:
34 if (unlikely(wait_for_completion_interruptible(&done))) {
35 /*
36 * To avoid race condition with ffs_epfile_io_complete,
37 * dequeue the request first then check
38 * status. usb_ep_dequeue API should guarantee no race
39 * condition with req->complete callback.
40 */
41 usb_ep_dequeue(ep->ep, req);
42 interrupted = ep->status < 0;
43 }
44
45The problem is, that we end up being interrupted, dequeue the
46request, and exit.
47
48But then the irq triggers and we try calling complete() on the
49context pointer which points to now random stack space, which
50results in the panic.
51
52Alan Stern pointed out there is a bug here, in that the snippet
53above "assumes that usb_ep_dequeue() waits until the request has
54been completed." And that:
55
56 wait_for_completion(&done);
57
58Is needed right after the usb_ep_dequeue().
59
60Thus this patch implements that change. With it I no longer see
61the crashes on suspend or reboot.
62
63This issue seems to have been uncovered by behavioral changes in
64the dwc3 driver in commit fec9095bdef4e ("usb: dwc3: gadget:
65remove wait_end_transfer").
66
67Cc: Alan Stern <stern@rowland.harvard.edu>
68Cc: Felipe Balbi <balbi@kernel.org>
69Cc: Zeng Tao <prime.zeng@hisilicon.com>
70Cc: Jack Pham <jackp@codeaurora.org>
71Cc: Thinh Nguyen <thinh.nguyen@synopsys.com>
72Cc: Chen Yu <chenyu56@huawei.com>
73Cc: Jerry Zhang <zhangjerry@google.com>
74Cc: Lars-Peter Clausen <lars@metafoo.de>
75Cc: Vincent Pelletier <plr.vincent@gmail.com>
76Cc: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
77Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
78Cc: Linux USB List <linux-usb@vger.kernel.org>
79Suggested-by: Alan Stern <stern@rowland.harvard.edu>
80Signed-off-by: John Stultz <john.stultz@linaro.org>
81Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
82Signed-off-by: Sasha Levin <sashal@kernel.org>
83---
84 drivers/usb/gadget/function/f_fs.c | 1 +
85 1 file changed, 1 insertion(+)
86
87diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
88index 52e6897fa35a..79900c0b4f3a 100644
89--- a/drivers/usb/gadget/function/f_fs.c
90+++ b/drivers/usb/gadget/function/f_fs.c
91@@ -1009,6 +1009,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
92 * condition with req->complete callback.
93 */
94 usb_ep_dequeue(ep->ep, req);
95+ wait_for_completion(&done);
96 interrupted = ep->status < 0;
97 }
98
99--
1002.19.1
101