diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-05-22 11:46:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 16:29:48 -0700 |
commit | d4ead16f50f9ad30bdc7276ec8fee7a24c72f294 (patch) | |
tree | e1905abbc393cc4d73180dd7b9e1cf860378b590 /drivers/usb/usb-skeleton.c | |
parent | 55e5fdfa541ec7bf1b1613624ed4dd8cdacaa841 (diff) | |
download | op-kernel-dev-d4ead16f50f9ad30bdc7276ec8fee7a24c72f294.zip op-kernel-dev-d4ead16f50f9ad30bdc7276ec8fee7a24c72f294.tar.gz |
USB: prevent char device open/deregister race
This patch (as908) adds central protection in usbcore for the
prototypical race between opening and unregistering a char device.
The spinlock used to protect the minor-numbers array is replaced with
an rwsem, which can remain locked across a call to a driver's open()
method. This guarantees that open() and deregister() will be mutually
exclusive.
The private locks currently used in several individual drivers for
this purpose are no longer necessary, and the patch removes them. The
following USB drivers are affected: usblcd, idmouse, auerswald,
legousbtower, sisusbvga/sisusb, ldusb, adutux, iowarrior, and
usb-skeleton.
As a side effect of this change, usb_deregister_dev() must not be
called while holding a lock that is acquired by open(). Unfortunately
a number of drivers do this, but luckily the solution is simple: call
usb_deregister_dev() before acquiring the lock.
In addition to these changes (and their consequent code
simplifications), the patch fixes a use-after-free bug in adutux and a
race between open() and release() in iowarrior.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/usb-skeleton.c')
-rw-r--r-- | drivers/usb/usb-skeleton.c | 14 |
1 files changed, 0 insertions, 14 deletions
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 8432bf1..38f8e4d 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -34,9 +34,6 @@ static struct usb_device_id skel_table [] = { }; MODULE_DEVICE_TABLE(usb, skel_table); -/* to prevent a race between open and disconnect */ -static DEFINE_MUTEX(skel_open_lock); - /* Get a minor range for your devices from the usb maintainer */ #define USB_SKEL_MINOR_BASE 192 @@ -83,10 +80,8 @@ static int skel_open(struct inode *inode, struct file *file) subminor = iminor(inode); - mutex_lock(&skel_open_lock); interface = usb_find_interface(&skel_driver, subminor); if (!interface) { - mutex_unlock(&skel_open_lock); err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); retval = -ENODEV; @@ -95,15 +90,12 @@ static int skel_open(struct inode *inode, struct file *file) dev = usb_get_intfdata(interface); if (!dev) { - mutex_unlock(&skel_open_lock); retval = -ENODEV; goto exit; } /* increment our usage count for the device */ kref_get(&dev->kref); - /* now we can drop the lock */ - mutex_unlock(&skel_open_lock); /* prevent the device from being autosuspended */ retval = usb_autopm_get_interface(interface); @@ -368,23 +360,17 @@ static void skel_disconnect(struct usb_interface *interface) struct usb_skel *dev; int minor = interface->minor; - /* prevent skel_open() from racing skel_disconnect() */ - mutex_lock(&skel_open_lock); - dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); /* give back our minor */ usb_deregister_dev(interface, &skel_class); - mutex_unlock(&skel_open_lock); /* prevent more I/O from starting */ mutex_lock(&dev->io_mutex); dev->interface = NULL; mutex_unlock(&dev->io_mutex); - - /* decrement our usage count */ kref_put(&dev->kref, skel_delete); |