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