lkml.org 
[lkml]   [2016]   [Nov]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.2 006/152] usb: renesas_usbhs: fix NULL pointer dereference in xfer_work()
    3.2.84-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>

    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 <yoshihiro.shimoda.uh@renesas.com>
    Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
    [bwh: Backported to 3.2: adjust context]
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    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);
    }

    /*
    \
     
     \ /
      Last update: 2016-11-14 04:12    [W:4.337 / U:0.228 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site