Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S941111AbcKNDMC (ORCPT ); Sun, 13 Nov 2016 22:12:02 -0500 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:46179 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754169AbcKNCF4 (ORCPT ); Sun, 13 Nov 2016 21:05:56 -0500 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "Yoshihiro Shimoda" , "Felipe Balbi" Date: Mon, 14 Nov 2016 00:14:07 +0000 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) Subject: [PATCH 3.2 006/152] usb: renesas_usbhs: fix NULL pointer dereference in xfer_work() In-Reply-To: X-SA-Exim-Connect-IP: 2a02:8011:400e:2:6f00:88c8:c921:d332 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2545 Lines: 81 3.2.84-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Yoshihiro Shimoda commit 4fdef698383db07d829da567e0e405fc41ff3a89 upstream. This patch fixes an issue that the xfer_work() is possible to cause NULL pointer dereference if the usb cable is disconnected while data transfer is running. In such case, a gadget driver may call usb_ep_disable()) before xfer_work() is actually called. In this case, the usbhs_pkt_pop() will call usbhsf_fifo_unselect(), and then usbhs_pipe_to_fifo() in xfer_work() will return NULL. Fixes: e73a989 ("usb: renesas_usbhs: add DMAEngine support") Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings --- drivers/usb/renesas_usbhs/fifo.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -760,15 +760,22 @@ static void usbhsf_dma_prepare_tasklet(u { struct usbhs_pkt *pkt = (struct usbhs_pkt *)data; struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); + struct usbhs_fifo *fifo; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct scatterlist sg; struct dma_async_tx_descriptor *desc; - struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); + struct dma_chan *chan; struct device *dev = usbhs_priv_to_dev(priv); enum dma_data_direction dir; dma_cookie_t cookie; + unsigned long flags; + usbhs_lock(priv, flags); + fifo = usbhs_pipe_to_fifo(pipe); + if (!fifo) + goto xfer_work_end; + + chan = usbhsf_dma_chan_get(fifo, pkt); dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; sg_init_table(&sg, 1); @@ -781,7 +788,7 @@ static void usbhsf_dma_prepare_tasklet(u DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) - return; + goto xfer_work_end; desc->callback = usbhsf_dma_complete; desc->callback_param = pipe; @@ -789,7 +796,7 @@ static void usbhsf_dma_prepare_tasklet(u cookie = desc->tx_submit(desc); if (cookie < 0) { dev_err(dev, "Failed to submit dma descriptor\n"); - return; + goto xfer_work_end; } dev_dbg(dev, " %s %d (%d/ %d)\n", @@ -797,6 +804,9 @@ static void usbhsf_dma_prepare_tasklet(u usbhsf_dma_start(pipe, fifo); dma_async_issue_pending(chan); + +xfer_work_end: + usbhs_unlock(priv, flags); } /*