lkml.org 
[lkml]   [2021]   [Nov]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 014/121] usb: hub: Fix locking issues with address0_mutex
    Date
    From: Mathias Nyman <mathias.nyman@linux.intel.com>

    commit 6cca13de26eea6d32a98d96d916a048d16a12822 upstream.

    Fix the circular lock dependency and unbalanced unlock of addess0_mutex
    introduced when fixing an address0_mutex enumeration retry race in commit
    ae6dc22d2d1 ("usb: hub: Fix usb enumeration issue due to address0 race")

    Make sure locking order between port_dev->status_lock and address0_mutex
    is correct, and that address0_mutex is not unlocked in hub_port_connect
    "done:" codepath which may be reached without locking address0_mutex

    Fixes: 6ae6dc22d2d1 ("usb: hub: Fix usb enumeration issue due to address0 race")
    Cc: <stable@vger.kernel.org>
    Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
    Tested-by: Hans de Goede <hdegoede@redhat.com>
    Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
    Acked-by: Hans de Goede <hdegoede@redhat.com>
    Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
    Link: https://lore.kernel.org/r/20211123101656.1113518-1-mathias.nyman@linux.intel.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/usb/core/hub.c | 20 ++++++++++++--------
    1 file changed, 12 insertions(+), 8 deletions(-)

    --- a/drivers/usb/core/hub.c
    +++ b/drivers/usb/core/hub.c
    @@ -5112,6 +5112,7 @@ static void hub_port_connect(struct usb_
    struct usb_port *port_dev = hub->ports[port1 - 1];
    struct usb_device *udev = port_dev->child;
    static int unreliable_port = -1;
    + bool retry_locked;

    /* Disconnect any existing devices under this port */
    if (udev) {
    @@ -5168,10 +5169,10 @@ static void hub_port_connect(struct usb_

    status = 0;

    - mutex_lock(hcd->address0_mutex);
    -
    for (i = 0; i < PORT_INIT_TRIES; i++) {
    -
    + usb_lock_port(port_dev);
    + mutex_lock(hcd->address0_mutex);
    + retry_locked = true;
    /* reallocate for each attempt, since references
    * to the previous one can escape in various ways
    */
    @@ -5179,6 +5180,8 @@ static void hub_port_connect(struct usb_
    if (!udev) {
    dev_err(&port_dev->dev,
    "couldn't allocate usb_device\n");
    + mutex_unlock(hcd->address0_mutex);
    + usb_unlock_port(port_dev);
    goto done;
    }

    @@ -5200,13 +5203,13 @@ static void hub_port_connect(struct usb_
    }

    /* reset (non-USB 3.0 devices) and get descriptor */
    - usb_lock_port(port_dev);
    status = hub_port_init(hub, udev, port1, i);
    - usb_unlock_port(port_dev);
    if (status < 0)
    goto loop;

    mutex_unlock(hcd->address0_mutex);
    + usb_unlock_port(port_dev);
    + retry_locked = false;

    if (udev->quirks & USB_QUIRK_DELAY_INIT)
    msleep(2000);
    @@ -5296,11 +5299,14 @@ static void hub_port_connect(struct usb_

    loop_disable:
    hub_port_disable(hub, port1, 1);
    - mutex_lock(hcd->address0_mutex);
    loop:
    usb_ep0_reinit(udev);
    release_devnum(udev);
    hub_free_dev(udev);
    + if (retry_locked) {
    + mutex_unlock(hcd->address0_mutex);
    + usb_unlock_port(port_dev);
    + }
    usb_put_dev(udev);
    if ((status == -ENOTCONN) || (status == -ENOTSUPP))
    break;
    @@ -5323,8 +5329,6 @@ loop:
    }

    done:
    - mutex_unlock(hcd->address0_mutex);
    -
    hub_port_disable(hub, port1, 1);
    if (hcd->driver->relinquish_port && !hub->hdev->parent) {
    if (status != -ENOTCONN && status != -ENODEV)

    \
     
     \ /
      Last update: 2021-11-29 23:40    [W:4.373 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site