On Mon, 3 Mar 2014, Dan Williams wrote:

> > In general I agree, and I like the compartmentalization of only needing
> > to take the lock in hub.c.  But I still think we have a hole with a
> > scenario like the following (granted, this should never happen in
> > current code...):
> >
> > CPU1                            CPU2
> > usb_remove_hcd(hcdA)
> > ...
> >   mutex_lock(peer_lock)
> >   hdevA->maxchild = 0;
> >   mutex_unlock(peer_lock)
> >                                 usb_add_hcd(hcdB)
> >                                 ...
> >                                   mutex_lock(peer_lock)
> >                                   hdevA = hcdA->self.root_hub
> >   usb_put_dev(hdevA) // free
> >                                   hubA = usb_hub_to_struct_hub(hdevA) // 
> > use after free
> 
> ...and if this is a hole then so is the hcdA->self.root_hub.  It makes
> sense that when the host controller breaks the peering relationship at
> the root it should hold the lock and clear ->shared_hcd and
> ->primary_hcd.

Yes, you jogged my thinking.  In addition to this hole, there is 
another section of the patch I completely forgot about.  The following 
needs to be added on to what I posted before.

Alan Stern



Index: usb-3.14/drivers/usb/core/hub.c
===================================================================
--- usb-3.14.orig/drivers/usb/core/hub.c
+++ usb-3.14/drivers/usb/core/hub.c
@@ -4564,6 +4564,8 @@ static void hub_port_connect_change(stru
                 */
                status = 0;
 
+               mutex_lock(&usb_port_peer_mutex);
+
                /* We mustn't add new devices if the parent hub has
                 * been disconnected; we would race with the
                 * recursively_mark_NOTATTACHED() routine.
@@ -4574,14 +4576,17 @@ static void hub_port_connect_change(stru
                else
                        hub->ports[port1 - 1]->child = udev;
                spin_unlock_irq(&device_state_lock);
+               mutex_unlock(&usb_port_peer_mutex);
 
                /* Run it through the hoops (find a driver, etc) */
                if (!status) {
                        status = usb_new_device(udev);
                        if (status) {
+                               mutex_lock(&usb_port_peer_mutex);
                                spin_lock_irq(&device_state_lock);
                                hub->ports[port1 - 1]->child = NULL;
                                spin_unlock_irq(&device_state_lock);
+                               mutex_unlock(&usb_port_peer_mutex);
                        }
                }
 

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

Reply via email to