]>
Commit | Line | Data |
---|---|---|
05528cff GKH |
1 | From c85400f886e3d41e69966470879f635a2b50084c Mon Sep 17 00:00:00 2001 |
2 | From: Jia-Ju Bai <baijiaju1990@gmail.com> | |
3 | Date: Tue, 18 Dec 2018 20:04:25 +0800 | |
4 | Subject: usb: r8a66597: Fix a possible concurrency use-after-free bug in r8a66597_endpoint_disable() | |
5 | ||
6 | From: Jia-Ju Bai <baijiaju1990@gmail.com> | |
7 | ||
8 | commit c85400f886e3d41e69966470879f635a2b50084c upstream. | |
9 | ||
10 | The function r8a66597_endpoint_disable() and r8a66597_urb_enqueue() may | |
11 | be concurrently executed. | |
12 | The two functions both access a possible shared variable "hep->hcpriv". | |
13 | ||
14 | This shared variable is freed by r8a66597_endpoint_disable() via the | |
15 | call path: | |
16 | r8a66597_endpoint_disable | |
17 | kfree(hep->hcpriv) (line 1995 in Linux-4.19) | |
18 | ||
19 | This variable is read by r8a66597_urb_enqueue() via the call path: | |
20 | r8a66597_urb_enqueue | |
21 | spin_lock_irqsave(&r8a66597->lock) | |
22 | init_pipe_info | |
23 | enable_r8a66597_pipe | |
24 | pipe = hep->hcpriv (line 802 in Linux-4.19) | |
25 | ||
26 | The read operation is protected by a spinlock, but the free operation | |
27 | is not protected by this spinlock, thus a concurrency use-after-free bug | |
28 | may occur. | |
29 | ||
30 | To fix this bug, the spin-lock and spin-unlock function calls in | |
31 | r8a66597_endpoint_disable() are moved to protect the free operation. | |
32 | ||
33 | Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com> | |
34 | Cc: stable <stable@vger.kernel.org> | |
35 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
36 | ||
37 | --- | |
38 | drivers/usb/host/r8a66597-hcd.c | 5 ++++- | |
39 | 1 file changed, 4 insertions(+), 1 deletion(-) | |
40 | ||
41 | --- a/drivers/usb/host/r8a66597-hcd.c | |
42 | +++ b/drivers/usb/host/r8a66597-hcd.c | |
43 | @@ -1990,6 +1990,8 @@ static int r8a66597_urb_dequeue(struct u | |
44 | ||
45 | static void r8a66597_endpoint_disable(struct usb_hcd *hcd, | |
46 | struct usb_host_endpoint *hep) | |
47 | +__acquires(r8a66597->lock) | |
48 | +__releases(r8a66597->lock) | |
49 | { | |
50 | struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); | |
51 | struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv; | |
52 | @@ -2002,13 +2004,14 @@ static void r8a66597_endpoint_disable(st | |
53 | return; | |
54 | pipenum = pipe->info.pipenum; | |
55 | ||
56 | + spin_lock_irqsave(&r8a66597->lock, flags); | |
57 | if (pipenum == 0) { | |
58 | kfree(hep->hcpriv); | |
59 | hep->hcpriv = NULL; | |
60 | + spin_unlock_irqrestore(&r8a66597->lock, flags); | |
61 | return; | |
62 | } | |
63 | ||
64 | - spin_lock_irqsave(&r8a66597->lock, flags); | |
65 | pipe_stop(r8a66597, pipe); | |
66 | pipe_irq_disable(r8a66597, pipenum); | |
67 | disable_irq_empty(r8a66597, pipenum); |