3.16.65-rc1 review patch. If anyone has any objections, please let me know.
------------------
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 Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- 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);