lkml.org 
[lkml]   [2012]   [Sep]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 212/218] USB: Fix race condition when removing host controllers
    Date
    3.4-stable review patch.  If anyone has any objections, please let me know.

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

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

    commit 0d00dc2611abbe6ad244d50569c2ee82ce42846c upstream.

    This patch (as1607) fixes a race that can occur if a USB host
    controller is removed while a process is reading the
    /sys/kernel/debug/usb/devices file.

    The usb_device_read() routine uses the bus->root_hub pointer to
    determine whether or not the root hub is registered. The is not a
    valid test, because the pointer is set before the root hub gets
    registered and remains set even after the root hub is unregistered and
    deallocated. As a result, usb_device_read() or usb_device_dump() can
    access freed memory, causing an oops.

    The patch changes the test to use the hcd->rh_registered flag, which
    does get set and cleared at the appropriate times. It also makes sure
    to hold the usb_bus_list_lock mutex while setting the flag, so that
    usb_device_read() will become aware of new root hubs as soon as they
    are registered.

    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Reported-by: Don Zickus <dzickus@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/core/devices.c | 2 +-
    drivers/usb/core/hcd.c | 6 ++----
    2 files changed, 3 insertions(+), 5 deletions(-)

    --- a/drivers/usb/core/devices.c
    +++ b/drivers/usb/core/devices.c
    @@ -624,7 +624,7 @@ static ssize_t usb_device_read(struct fi
    /* print devices for all busses */
    list_for_each_entry(bus, &usb_bus_list, bus_list) {
    /* recurse through all children of the root hub */
    - if (!bus->root_hub)
    + if (!bus_to_hcd(bus)->rh_registered)
    continue;
    usb_lock_device(bus->root_hub);
    ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos,
    --- a/drivers/usb/core/hcd.c
    +++ b/drivers/usb/core/hcd.c
    @@ -1002,10 +1002,7 @@ static int register_root_hub(struct usb_
    if (retval) {
    dev_err (parent_dev, "can't register root hub for %s, %d\n",
    dev_name(&usb_dev->dev), retval);
    - }
    - mutex_unlock(&usb_bus_list_lock);
    -
    - if (retval == 0) {
    + } else {
    spin_lock_irq (&hcd_root_hub_lock);
    hcd->rh_registered = 1;
    spin_unlock_irq (&hcd_root_hub_lock);
    @@ -1014,6 +1011,7 @@ static int register_root_hub(struct usb_
    if (HCD_DEAD(hcd))
    usb_hc_died (hcd); /* This time clean up */
    }
    + mutex_unlock(&usb_bus_list_lock);

    return retval;
    }



    \
     
     \ /
      Last update: 2012-09-29 00:01    [W:2.171 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site