aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/misc/iowarrior.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/misc/iowarrior.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/misc/iowarrior.c')
-rw-r--r--drivers/usb/misc/iowarrior.c26
1 files changed, 8 insertions, 18 deletions
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 3bb33f7bfa36..28548d186712 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -100,8 +100,6 @@ struct iowarrior {
100/*--------------*/ 100/*--------------*/
101/* globals */ 101/* globals */
102/*--------------*/ 102/*--------------*/
103/* prevent races between open() and disconnect() */
104static DECLARE_MUTEX(disconnect_sem);
105 103
106/* 104/*
107 * USB spec identifies 5 second timeouts. 105 * USB spec identifies 5 second timeouts.
@@ -600,22 +598,18 @@ static int iowarrior_open(struct inode *inode, struct file *file)
600 598
601 subminor = iminor(inode); 599 subminor = iminor(inode);
602 600
603 /* prevent disconnects */
604 down(&disconnect_sem);
605
606 interface = usb_find_interface(&iowarrior_driver, subminor); 601 interface = usb_find_interface(&iowarrior_driver, subminor);
607 if (!interface) { 602 if (!interface) {
608 err("%s - error, can't find device for minor %d", __FUNCTION__, 603 err("%s - error, can't find device for minor %d", __FUNCTION__,
609 subminor); 604 subminor);
610 retval = -ENODEV; 605 return -ENODEV;
611 goto out;
612 } 606 }
613 607
614 dev = usb_get_intfdata(interface); 608 dev = usb_get_intfdata(interface);
615 if (!dev) { 609 if (!dev)
616 retval = -ENODEV; 610 return -ENODEV;
617 goto out; 611
618 } 612 mutex_lock(&dev->mutex);
619 613
620 /* Only one process can open each device, no sharing. */ 614 /* Only one process can open each device, no sharing. */
621 if (dev->opened) { 615 if (dev->opened) {
@@ -636,7 +630,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
636 retval = 0; 630 retval = 0;
637 631
638out: 632out:
639 up(&disconnect_sem); 633 mutex_unlock(&dev->mutex);
640 return retval; 634 return retval;
641} 635}
642 636
@@ -868,19 +862,16 @@ static void iowarrior_disconnect(struct usb_interface *interface)
868 struct iowarrior *dev; 862 struct iowarrior *dev;
869 int minor; 863 int minor;
870 864
871 /* prevent races with open() */
872 down(&disconnect_sem);
873
874 dev = usb_get_intfdata(interface); 865 dev = usb_get_intfdata(interface);
875 usb_set_intfdata(interface, NULL); 866 usb_set_intfdata(interface, NULL);
876 867
877 mutex_lock(&dev->mutex);
878
879 minor = dev->minor; 868 minor = dev->minor;
880 869
881 /* give back our minor */ 870 /* give back our minor */
882 usb_deregister_dev(interface, &iowarrior_class); 871 usb_deregister_dev(interface, &iowarrior_class);
883 872
873 mutex_lock(&dev->mutex);
874
884 /* prevent device read, write and ioctl */ 875 /* prevent device read, write and ioctl */
885 dev->present = 0; 876 dev->present = 0;
886 877
@@ -898,7 +889,6 @@ static void iowarrior_disconnect(struct usb_interface *interface)
898 /* no process is using the device, cleanup now */ 889 /* no process is using the device, cleanup now */
899 iowarrior_delete(dev); 890 iowarrior_delete(dev);
900 } 891 }
901 up(&disconnect_sem);
902 892
903 dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", 893 dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
904 minor - IOWARRIOR_MINOR_BASE); 894 minor - IOWARRIOR_MINOR_BASE);