Re: Re: Re: Re: Re: [PATCH] usb: core: fix a double free in the usb driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Felipe:

Can you check the reasoning here?  I don't understand how an OTG 
event could cause dwc3 to remove the shared (SuperSpeed) hcd and then 
re-instantiate it before removing the primary (HS-FS-LS) hcd, which is 
what this diagram seems to show.

On Wed, 8 Jun 2016, Chung-Geol Kim wrote:

> Thank you for clear understanding the problem that I faced.
> When I tested with your below patch, it also works well.
> The description has been modified as follows as you suggested.
> 
> =================================================
>      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
>                            |__________________|
> 
> =================================================

As far as I can tell, the real problem occurs when the HS/FS/LS primary
hcd is released before the SS shared hcd.  The bandwidth_mutex gets
deallocated when the primary hcd is released, even though the shared
hcd still exists.  Then when the shared hcd is released, it tries the
deallocate the bandwidth_mutex a second time, because the code is 
written in such a way that it now thinks the shared hcd _is_ the 
primary.

Is the patch below a good way to fix the problem?  There doesn't _seem_
to be any harm in making this change.  At least, I don't think it will 
confuse drivers any more than they are already.

Thanks,

Alan Stern


Index: usb-4.x/drivers/usb/core/hcd.c
===================================================================
--- usb-4.x.orig/drivers/usb/core/hcd.c
+++ usb-4.x/drivers/usb/core/hcd.c
@@ -2588,24 +2588,22 @@ EXPORT_SYMBOL_GPL(usb_create_hcd);
  * Don't deallocate the bandwidth_mutex until the last shared usb_hcd is
  * deallocated.
  *
- * Make sure to only deallocate the bandwidth_mutex when the primary HCD is
- * freed.  When hcd_release() is called for either hcd in a peer set
- * invalidate the peer's ->shared_hcd and ->primary_hcd pointers to
- * block new peering attempts
+ * Make sure to deallocate the bandwidth_mutex only when the last HCD is
+ * freed.  When hcd_release() is called for either hcd in a peer set,
+ * invalidate the peer's ->shared_hcd and ->primary_hcd pointers.
  */
 static void hcd_release(struct kref *kref)
 {
 	struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
 
 	mutex_lock(&usb_port_peer_mutex);
-	if (usb_hcd_is_primary_hcd(hcd))
-		kfree(hcd->bandwidth_mutex);
 	if (hcd->shared_hcd) {
 		struct usb_hcd *peer = hcd->shared_hcd;
 
 		peer->shared_hcd = NULL;
-		if (peer->primary_hcd == hcd)
-			peer->primary_hcd = NULL;
+		peer->primary_hcd = NULL;
+	} else {
+		kfree(hcd->bandwidth_mutex);
 	}
 	mutex_unlock(&usb_port_peer_mutex);
 	kfree(hcd);

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux