aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/usb-skeleton.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-05-22 11:46:41 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:29:48 -0400
commitd4ead16f50f9ad30bdc7276ec8fee7a24c72f294 (patch)
treee1905abbc393cc4d73180dd7b9e1cf860378b590 /drivers/usb/usb-skeleton.c
parent55e5fdfa541ec7bf1b1613624ed4dd8cdacaa841 (diff)
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.c14
1 files changed, 0 insertions, 14 deletions
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 8432bf171d2e..38f8e4df9dd6 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -34,9 +34,6 @@ static struct usb_device_id skel_table [] = {
34}; 34};
35MODULE_DEVICE_TABLE(usb, skel_table); 35MODULE_DEVICE_TABLE(usb, skel_table);
36 36
37/* to prevent a race between open and disconnect */
38static DEFINE_MUTEX(skel_open_lock);
39
40 37
41/* Get a minor range for your devices from the usb maintainer */ 38/* Get a minor range for your devices from the usb maintainer */
42#define USB_SKEL_MINOR_BASE 192 39#define USB_SKEL_MINOR_BASE 192
@@ -83,10 +80,8 @@ static int skel_open(struct inode *inode, struct file *file)
83 80
84 subminor = iminor(inode); 81 subminor = iminor(inode);
85 82
86 mutex_lock(&skel_open_lock);
87 interface = usb_find_interface(&skel_driver, subminor); 83 interface = usb_find_interface(&skel_driver, subminor);
88 if (!interface) { 84 if (!interface) {
89 mutex_unlock(&skel_open_lock);
90 err ("%s - error, can't find device for minor %d", 85 err ("%s - error, can't find device for minor %d",
91 __FUNCTION__, subminor); 86 __FUNCTION__, subminor);
92 retval = -ENODEV; 87 retval = -ENODEV;
@@ -95,15 +90,12 @@ static int skel_open(struct inode *inode, struct file *file)
95 90
96 dev = usb_get_intfdata(interface); 91 dev = usb_get_intfdata(interface);
97 if (!dev) { 92 if (!dev) {
98 mutex_unlock(&skel_open_lock);
99 retval = -ENODEV; 93 retval = -ENODEV;
100 goto exit; 94 goto exit;
101 } 95 }
102 96
103 /* increment our usage count for the device */ 97 /* increment our usage count for the device */
104 kref_get(&dev->kref); 98 kref_get(&dev->kref);
105 /* now we can drop the lock */
106 mutex_unlock(&skel_open_lock);
107 99
108 /* prevent the device from being autosuspended */ 100 /* prevent the device from being autosuspended */
109 retval = usb_autopm_get_interface(interface); 101 retval = usb_autopm_get_interface(interface);
@@ -368,23 +360,17 @@ static void skel_disconnect(struct usb_interface *interface)
368 struct usb_skel *dev; 360 struct usb_skel *dev;
369 int minor = interface->minor; 361 int minor = interface->minor;
370 362
371 /* prevent skel_open() from racing skel_disconnect() */
372 mutex_lock(&skel_open_lock);
373
374 dev = usb_get_intfdata(interface); 363 dev = usb_get_intfdata(interface);
375 usb_set_intfdata(interface, NULL); 364 usb_set_intfdata(interface, NULL);
376 365
377 /* give back our minor */ 366 /* give back our minor */
378 usb_deregister_dev(interface, &skel_class); 367 usb_deregister_dev(interface, &skel_class);
379 mutex_unlock(&skel_open_lock);
380 368
381 /* prevent more I/O from starting */ 369 /* prevent more I/O from starting */
382 mutex_lock(&dev->io_mutex); 370 mutex_lock(&dev->io_mutex);
383 dev->interface = NULL; 371 dev->interface = NULL;
384 mutex_unlock(&dev->io_mutex); 372 mutex_unlock(&dev->io_mutex);
385 373
386
387
388 /* decrement our usage count */ 374 /* decrement our usage count */
389 kref_put(&dev->kref, skel_delete); 375 kref_put(&dev->kref, skel_delete);
390 376