lkml.org 
[lkml]   [2016]   [Jan]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.19.y-ckt 122/160] USB: fix invalid memory access in hub_activate()
    Date
    3.19.8-ckt13 -stable review patch.  If anyone has any objections, please let me know.

    ---8<------------------------------------------------------------

    From: Alan Stern <stern@rowland.harvard.edu>

    commit e50293ef9775c5f1cf3fcc093037dd6a8c5684ea upstream.

    Commit 8520f38099cc ("USB: change hub initialization sleeps to
    delayed_work") changed the hub_activate() routine to make part of it
    run in a workqueue. However, the commit failed to take a reference to
    the usb_hub structure or to lock the hub interface while doing so. As
    a result, if a hub is plugged in and quickly unplugged before the work
    routine can run, the routine will try to access memory that has been
    deallocated. Or, if the hub is unplugged while the routine is
    running, the memory may be deallocated while it is in active use.

    This patch fixes the problem by taking a reference to the usb_hub at
    the start of hub_activate() and releasing it at the end (when the work
    is finished), and by locking the hub interface while the work routine
    is running. It also adds a check at the start of the routine to see
    if the hub has already been disconnected, in which nothing should be
    done.

    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Reported-by: Alexandru Cornea <alexandru.cornea@intel.com>
    Tested-by: Alexandru Cornea <alexandru.cornea@intel.com>
    Fixes: 8520f38099cc ("USB: change hub initialization sleeps to delayed_work")
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Kamal Mostafa <kamal@canonical.com>
    ---
    drivers/usb/core/hub.c | 22 +++++++++++++++++++---
    1 file changed, 19 insertions(+), 3 deletions(-)

    diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
    index 5f719cb..fde1e10 100644
    --- a/drivers/usb/core/hub.c
    +++ b/drivers/usb/core/hub.c
    @@ -1034,10 +1034,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
    unsigned delay;

    /* Continue a partial initialization */
    - if (type == HUB_INIT2)
    - goto init2;
    - if (type == HUB_INIT3)
    + if (type == HUB_INIT2 || type == HUB_INIT3) {
    + device_lock(hub->intfdev);
    +
    + /* Was the hub disconnected while we were waiting? */
    + if (hub->disconnected) {
    + device_unlock(hub->intfdev);
    + kref_put(&hub->kref, hub_release);
    + return;
    + }
    + if (type == HUB_INIT2)
    + goto init2;
    goto init3;
    + }
    + kref_get(&hub->kref);

    /* The superspeed hub except for root hub has to use Hub Depth
    * value as an offset into the route string to locate the bits
    @@ -1235,6 +1245,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
    queue_delayed_work(system_power_efficient_wq,
    &hub->init_work,
    msecs_to_jiffies(delay));
    + device_unlock(hub->intfdev);
    return; /* Continues at init3: below */
    } else {
    msleep(delay);
    @@ -1256,6 +1267,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
    /* Allow autosuspend if it was suppressed */
    if (type <= HUB_INIT3)
    usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
    +
    + if (type == HUB_INIT2 || type == HUB_INIT3)
    + device_unlock(hub->intfdev);
    +
    + kref_put(&hub->kref, hub_release);
    }

    /* Implement the continuations for the delays above */
    --
    1.9.1

    \
     
     \ /
      Last update: 2016-01-20 03:01    [W:3.984 / U:0.168 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site