| From c85400f886e3d41e69966470879f635a2b50084c Mon Sep 17 00:00:00 2001 |
| From: Jia-Ju Bai <baijiaju1990@gmail.com> |
| Date: Tue, 18 Dec 2018 20:04:25 +0800 |
| Subject: usb: r8a66597: Fix a possible concurrency use-after-free bug in r8a66597_endpoint_disable() |
| |
| From: Jia-Ju Bai <baijiaju1990@gmail.com> |
| |
| commit c85400f886e3d41e69966470879f635a2b50084c upstream. |
| |
| The function r8a66597_endpoint_disable() and r8a66597_urb_enqueue() may |
| be concurrently executed. |
| The two functions both access a possible shared variable "hep->hcpriv". |
| |
| This shared variable is freed by r8a66597_endpoint_disable() via the |
| call path: |
| r8a66597_endpoint_disable |
| kfree(hep->hcpriv) (line 1995 in Linux-4.19) |
| |
| This variable is read by r8a66597_urb_enqueue() via the call path: |
| r8a66597_urb_enqueue |
| spin_lock_irqsave(&r8a66597->lock) |
| init_pipe_info |
| enable_r8a66597_pipe |
| pipe = hep->hcpriv (line 802 in Linux-4.19) |
| |
| The read operation is protected by a spinlock, but the free operation |
| is not protected by this spinlock, thus a concurrency use-after-free bug |
| may occur. |
| |
| To fix this bug, the spin-lock and spin-unlock function calls in |
| r8a66597_endpoint_disable() are moved to protect the free operation. |
| |
| Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com> |
| Cc: stable <stable@vger.kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/host/r8a66597-hcd.c | 5 ++++- |
| 1 file changed, 4 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/usb/host/r8a66597-hcd.c |
| +++ b/drivers/usb/host/r8a66597-hcd.c |
| @@ -1990,6 +1990,8 @@ static int r8a66597_urb_dequeue(struct u |
| |
| static void r8a66597_endpoint_disable(struct usb_hcd *hcd, |
| struct usb_host_endpoint *hep) |
| +__acquires(r8a66597->lock) |
| +__releases(r8a66597->lock) |
| { |
| struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); |
| struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv; |
| @@ -2002,13 +2004,14 @@ static void r8a66597_endpoint_disable(st |
| return; |
| pipenum = pipe->info.pipenum; |
| |
| + spin_lock_irqsave(&r8a66597->lock, flags); |
| if (pipenum == 0) { |
| kfree(hep->hcpriv); |
| hep->hcpriv = NULL; |
| + spin_unlock_irqrestore(&r8a66597->lock, flags); |
| return; |
| } |
| |
| - spin_lock_irqsave(&r8a66597->lock, flags); |
| pipe_stop(r8a66597, pipe); |
| pipe_irq_disable(r8a66597, pipenum); |
| disable_irq_empty(r8a66597, pipenum); |