Re: [PATCH] usb/core: Fix race condition when removing EHCI PCI devices

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

 



On Mon, 17 Sep 2012, Alan Stern wrote:

> On Mon, 17 Sep 2012, Don Zickus wrote:
> 
> > I have added some in-depth analysis from our customer.
> > 
> > 
> > The problem is that the failing routine was called with a pointer to usbdev in
> > memory that has already been freed and overwritten with the pool poison pattern.
> > This causes an access violation on line 502:
> 
> The stack trace shows that the failure occurred in usb_device_dump(), 
> which was called from usb_device_read().  Since it wasn't a recursive 
> call, the usbdev argument must have pointed to the root-hub device.
> 
> I don't see how this could have happened if the kernel included the 
> patch I sent earlier.  usb_device_read() holds the usb_bus_list_lock 
> mutex throughout, and it tests that the root hub's devnum field is not 
> equal to 0 before calling usb_dump_device().
> 
> Meanwhile, usb_remove_hcd() sets hcd->self.bus.root_hub->devnum to 0
> while holding usb_bus_list_lock, and it doesn't deallocate the root hub
> device until after the mutex is dropped.
> 
> Are you certain that the test was conducted with the patch in place?
> 
> If you want to track down what's going wrong, you'll have to add some 
> debugging code to usb_device_read() and usb_remove_hcd().  By the time 
> usb_device_dump() starts running, it's already too late.

After thinking about this some more, I realized that my patch still 
leaves a race -- although the oops would occur in a different place 
(where usb_device_read checks bus->root_hub->devnum).

Here's a different patch which should work better.  It relies on the
rh_registered flag in the usb_hcd structure, which persists as long as
the usb_bus structure does, rather than on anything stored in the
root-hub device structure.

Alan Stern



Index: usb-3.6/drivers/usb/core/devices.c
===================================================================
--- usb-3.6.orig/drivers/usb/core/devices.c
+++ usb-3.6/drivers/usb/core/devices.c
@@ -624,7 +624,7 @@ static ssize_t usb_device_read(struct fi
 	/* print devices for all busses */
 	list_for_each_entry(bus, &usb_bus_list, bus_list) {
 		/* recurse through all children of the root hub */
-		if (!bus->root_hub)
+		if (!bus_to_hcd(bus)->rh_registered)
 			continue;
 		usb_lock_device(bus->root_hub);
 		ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos,
Index: usb-3.6/drivers/usb/core/hcd.c
===================================================================
--- usb-3.6.orig/drivers/usb/core/hcd.c
+++ usb-3.6/drivers/usb/core/hcd.c
@@ -1011,10 +1011,7 @@ static int register_root_hub(struct usb_
 	if (retval) {
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
 				dev_name(&usb_dev->dev), retval);
-	}
-	mutex_unlock(&usb_bus_list_lock);
-
-	if (retval == 0) {
+	} else {
 		spin_lock_irq (&hcd_root_hub_lock);
 		hcd->rh_registered = 1;
 		spin_unlock_irq (&hcd_root_hub_lock);
@@ -1023,6 +1020,7 @@ static int register_root_hub(struct usb_
 		if (HCD_DEAD(hcd))
 			usb_hc_died (hcd);	/* This time clean up */
 	}
+	mutex_unlock(&usb_bus_list_lock);
 
 	return retval;
 }

--
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