Comment 1 for bug 1616318

Revision history for this message
AceLan Kao (acelankao) wrote :

This commit can fix this issue

commit ab2a4bf83902c170d29ba130a8abb5f9d90559e1
Author: Alan Stern <email address hidden>
Date: Mon Jun 27 10:23:10 2016 -0400

    USB: don't free bandwidth_mutex too early

    The USB core contains a bug that can show up when a USB-3 host
    controller is removed. If the primary (USB-2) hcd structure is
    released before the shared (USB-3) hcd, the core will try to do a
    double-free of the common bandwidth_mutex.

    The problem was described in graphical form by Chung-Geol Kim, who
    first reported it:

    =================================================
         At *remove USB(3.0) Storage
         sequence <1> --> <5> ((Problem Case))
    =================================================
                                      VOLD
    ------------------------------------|------------
                                     (uevent)
                                ________|_________
                               |<1> |
                               |dwc3_otg_sm_work |
                               |usb_put_hcd |
                               |peer_hcd(kref=2)|
                               |__________________|
                                ________|_________
                               |<2> |
                               |New USB BUS #2 |
                               | |
                               |peer_hcd(kref=1) |
                               | |
                             --(Link)-bandXX_mutex|
                             | |__________________|
                             |
        ___________________ |
       |<3> | |
       |dwc3_otg_sm_work | |
       |usb_put_hcd | |
       |primary_hcd(kref=1)| |
       |___________________| |
        _________|_________ |
       |<4> | |
       |New USB BUS #1 | |
       |hcd_release | |
       |primary_hcd(kref=0)| |
       | | |
       |bandXX_mutex(free) |<-
       |___________________|
                                   (( VOLD ))
                                ______|___________
                               |<5> |
                               | SCSI |
                               |usb_put_hcd |
                               |peer_hcd(kref=0) |
                               |*hcd_release |
                               |bandXX_mutex(free*)|<- double free
                               |__________________|

    =================================================

    This happens because hcd_release() frees the bandwidth_mutex whenever
    it sees a primary hcd being released (which is not a very good idea
    in any case), but in the course of releasing the primary hcd, it
    changes the pointers in the shared hcd in such a way that the shared
    hcd will appear to be primary when it gets released.

    This patch fixes the problem by changing hcd_release() so that it
    deallocates the bandwidth_mutex only when the _last_ hcd structure
    referencing it is released. The patch also removes an unnecessary
    test, so that when an hcd is released, both the shared_hcd and
    primary_hcd pointers in the hcd's peer will be cleared.

    Signed-off-by: Alan Stern <email address hidden>
    Reported-by: Chung-Geol Kim <email address hidden>
    Tested-by: Chung-Geol Kim <email address hidden>
    CC: <email address hidden>
    Signed-off-by: Greg Kroah-Hartman <email address hidden>