lkml.org 
[lkml]   [2019]   [Aug]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 57/78] USB: core: Fix races in character device registration and deregistraion
    Date
    From: Alan Stern <stern@rowland.harvard.edu>

    commit 303911cfc5b95d33687d9046133ff184cf5043ff upstream.

    The syzbot fuzzer has found two (!) races in the USB character device
    registration and deregistration routines. This patch fixes the races.

    The first race results from the fact that usb_deregister_dev() sets
    usb_minors[intf->minor] to NULL before calling device_destroy() on the
    class device. This leaves a window during which another thread can
    allocate the same minor number but will encounter a duplicate name
    error when it tries to register its own class device. A typical error
    message in the system log would look like:

    sysfs: cannot create duplicate filename '/class/usbmisc/ldusb0'

    The patch fixes this race by destroying the class device first.

    The second race is in usb_register_dev(). When that routine runs, it
    first allocates a minor number, then drops minor_rwsem, and then
    creates the class device. If the device creation fails, the minor
    number is deallocated and the whole routine returns an error. But
    during the time while minor_rwsem was dropped, there is a window in
    which the minor number is allocated and so another thread can
    successfully open the device file. Typically this results in
    use-after-free errors or invalid accesses when the other thread closes
    its open file reference, because the kernel then tries to release
    resources that were already deallocated when usb_register_dev()
    failed. The patch fixes this race by keeping minor_rwsem locked
    throughout the entire routine.

    Reported-and-tested-by: syzbot+30cf45ebfe0b0c4847a1@syzkaller.appspotmail.com
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    CC: <stable@vger.kernel.org>
    Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1908121607590.1659-100000@iolanthe.rowland.org
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/core/file.c | 10 +++++-----
    1 file changed, 5 insertions(+), 5 deletions(-)

    --- a/drivers/usb/core/file.c
    +++ b/drivers/usb/core/file.c
    @@ -191,9 +191,10 @@ int usb_register_dev(struct usb_interfac
    intf->minor = minor;
    break;
    }
    - up_write(&minor_rwsem);
    - if (intf->minor < 0)
    + if (intf->minor < 0) {
    + up_write(&minor_rwsem);
    return -EXFULL;
    + }

    /* create a usb class device for this usb interface */
    snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
    @@ -206,12 +207,11 @@ int usb_register_dev(struct usb_interfac
    MKDEV(USB_MAJOR, minor), class_driver,
    "%s", temp);
    if (IS_ERR(intf->usb_dev)) {
    - down_write(&minor_rwsem);
    usb_minors[minor] = NULL;
    intf->minor = -1;
    - up_write(&minor_rwsem);
    retval = PTR_ERR(intf->usb_dev);
    }
    + up_write(&minor_rwsem);
    return retval;
    }
    EXPORT_SYMBOL_GPL(usb_register_dev);
    @@ -237,12 +237,12 @@ void usb_deregister_dev(struct usb_inter
    return;

    dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
    + device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));

    down_write(&minor_rwsem);
    usb_minors[intf->minor] = NULL;
    up_write(&minor_rwsem);

    - device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
    intf->usb_dev = NULL;
    intf->minor = -1;
    destroy_usb_class();

    \
     
     \ /
      Last update: 2019-08-22 19:29    [W:4.801 / U:0.332 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site