lkml.org 
[lkml]   [2014]   [Jun]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.10 31/52] USB: cdc-acm: fix write and resume race
    Date
    3.10-stable review patch.  If anyone has any objections, please let me know.

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

    From: Johan Hovold <jhovold@gmail.com>

    commit e144ed28bed10684f9aaec6325ed974d53f76110 upstream.

    Fix race between write() and resume() due to improper locking that could
    lead to writes being reordered.

    Resume must be done atomically and susp_count be protected by the
    write_lock in order to prevent racing with write(). This could otherwise
    lead to writes being reordered if write() grabs the write_lock after
    susp_count is decremented, but before the delayed urb is submitted.

    Fixes: 11ea859d64b6 ("USB: additional power savings for cdc-acm devices
    that support remote wakeup")

    Signed-off-by: Johan Hovold <jhovold@gmail.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/class/cdc-acm.c | 23 +++++++++--------------
    1 file changed, 9 insertions(+), 14 deletions(-)

    --- a/drivers/usb/class/cdc-acm.c
    +++ b/drivers/usb/class/cdc-acm.c
    @@ -1461,27 +1461,20 @@ static int acm_resume(struct usb_interfa
    struct acm *acm = usb_get_intfdata(intf);
    struct acm_wb *wb;
    int rv = 0;
    - int cnt;

    spin_lock_irq(&acm->read_lock);
    - acm->susp_count -= 1;
    - cnt = acm->susp_count;
    - spin_unlock_irq(&acm->read_lock);
    + spin_lock(&acm->write_lock);

    - if (cnt)
    - return 0;
    + if (--acm->susp_count)
    + goto out;

    if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
    - rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
    + rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);

    - spin_lock_irq(&acm->write_lock);
    if (acm->delayed_wb) {
    wb = acm->delayed_wb;
    acm->delayed_wb = NULL;
    - spin_unlock_irq(&acm->write_lock);
    acm_start_wb(acm, wb);
    - } else {
    - spin_unlock_irq(&acm->write_lock);
    }

    /*
    @@ -1489,12 +1482,14 @@ static int acm_resume(struct usb_interfa
    * do the write path at all cost
    */
    if (rv < 0)
    - goto err_out;
    + goto out;

    - rv = acm_submit_read_urbs(acm, GFP_NOIO);
    + rv = acm_submit_read_urbs(acm, GFP_ATOMIC);
    }
    +out:
    + spin_unlock(&acm->write_lock);
    + spin_unlock_irq(&acm->read_lock);

    -err_out:
    return rv;
    }




    \
     
     \ /
      Last update: 2014-06-24 22:21    [W:4.093 / U:0.100 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site