Re: [GIT PATCH] USB patches for 2.6.33-git

From: Russ Dill
Date: Mon Dec 14 2009 - 23:45:55 EST


On Mon, 2009-12-14 at 20:36 -0800, Linus Torvalds wrote:
>
> On Mon, 14 Dec 2009, Russ Dill wrote:
> > @@ -144,10 +144,9 @@ static int __find_interface(struct device *dev, void *data)
> > return 0;
> >
> > intf = to_usb_interface(dev);
> > - if (intf->minor != -1 && intf->minor == arg->minor) {
> > - arg->interface = intf;
> > + if (intf->minor != -1 && intf->minor == arg->minor &&
> > + dev->driver == arg->drv)
> > return 1;
> > - }
> > return 0;
> > }
>
> Btw, can we please write this somewhat more readably, and just do
>
> if (dev->driver != arg->drv)
> return 0;
> intf = to_usb_interface(dev);
> return intf->minor == arg->minor;
>
> because the whole "intf->minor != -1" thing is pointless (we're going to
> test it against 'arg->minor', and if that is -1, then the caller damn well
> gets what he deserves anyway).
>
> This way there are no complex multi-line crud expressions, and it all
> looks simpler. No?

Yup.

From 41e394bc38b9d5224cc5e8013f45e769910a114e Mon Sep 17 00:00:00 2001
From: Russ Dill <Russ.Dill@xxxxxxxxx>
Date: Wed, 18 Nov 2009 10:31:27 -0700
Subject: [PATCH] Close usb_find_interface race v3

USB drivers that create character devices call usb_register_dev in their
probe function. This associates the usb_interface device with that minor
number and creates the character device and announces it to the world.
However, the driver's probe function is called before the new
usb_interface is added to the driver's klist_devices.

This is a problem because userspace will respond to the character device
creation announcement by opening the character device. The driver's open
function will the call usb_find_interface to find the usb_interface
associated with that minor number. usb_find_interface will walk the
driver's list of devices and find the usb_interface with the matching
minor number.

Because the announcement happens before the usb_interface is added to the
driver's klist_devices, a race condition exists. A straightforward fix
is to walk the list of devices on usb_bus_type instead since the device
is added to that list before the announcement occurs.

bus_find_device calls get_device to bump the reference count on the found
device. It is arguable that the reference count should be dropped by the
caller of usb_find_interface instead of usb_find_interface, however,
the current users of usb_find_interface do not expect this.

The original version of this patch only matched against minor number
instead of driver and minor number. This version matches against both.

Signed-off-by: Russ Dill <Russ.Dill@xxxxxxxxx>
---
drivers/usb/core/usb.c | 31 ++++++++++++++++---------------
1 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index b1b85ab..52e5e31 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting);

struct find_interface_arg {
int minor;
- struct usb_interface *interface;
+ struct device_driver *drv;
};

static int __find_interface(struct device *dev, void *data)
@@ -143,12 +143,10 @@ static int __find_interface(struct device *dev, void *data)
if (!is_usb_interface(dev))
return 0;

+ if (dev->driver != arg->drv)
+ return 0;
intf = to_usb_interface(dev);
- if (intf->minor != -1 && intf->minor == arg->minor) {
- arg->interface = intf;
- return 1;
- }
- return 0;
+ return intf->minor == arg->minor;
}

/**
@@ -156,21 +154,24 @@ static int __find_interface(struct device *dev, void *data)
* @drv: the driver whose current configuration is considered
* @minor: the minor number of the desired device
*
- * This walks the driver device list and returns a pointer to the interface
- * with the matching minor. Note, this only works for devices that share the
- * USB major number.
+ * This walks the bus device list and returns a pointer to the interface
+ * with the matching minor and driver. Note, this only works for devices
+ * that share the USB major number.
*/
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
struct find_interface_arg argb;
- int retval;
+ struct device *dev;

argb.minor = minor;
- argb.interface = NULL;
- /* eat the error, it will be in argb.interface */
- retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb,
- __find_interface);
- return argb.interface;
+ argb.drv = &drv->drvwrap.driver;
+
+ dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface);
+
+ /* Drop reference count from bus_find_device */
+ put_device(dev);
+
+ return dev ? to_usb_interface(dev) : NULL;
}
EXPORT_SYMBOL_GPL(usb_find_interface);

--
1.6.5




Attachment: signature.asc
Description: This is a digitally signed message part