Browse Source

USB: open disconnect race in usblcd

this driver has a possible use after free due to a race when disconnect
and open handle intfdata without a lock.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Oliver Neukum 17 years ago
parent
commit
d5d1ceac2a
1 changed files with 10 additions and 1 deletions
  1. 10 1
      drivers/usb/misc/usblcd.c

+ 10 - 1
drivers/usb/misc/usblcd.c

@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 
 
@@ -34,6 +35,8 @@ static struct usb_device_id id_table [] = {
 };
 };
 MODULE_DEVICE_TABLE (usb, id_table);
 MODULE_DEVICE_TABLE (usb, id_table);
 
 
+static DEFINE_MUTEX(open_disc_mutex);
+
 
 
 struct usb_lcd {
 struct usb_lcd {
 	struct usb_device *	udev;			/* init: probe_lcd */
 	struct usb_device *	udev;			/* init: probe_lcd */
@@ -79,12 +82,16 @@ static int lcd_open(struct inode *inode, struct file *file)
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
+	mutex_lock(&open_disc_mutex);
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
-	if (!dev)
+	if (!dev) {
+		mutex_unlock(&open_disc_mutex);
 		return -ENODEV;
 		return -ENODEV;
+	}
 
 
 	/* increment our usage count for the device */
 	/* increment our usage count for the device */
 	kref_get(&dev->kref);
 	kref_get(&dev->kref);
+	mutex_unlock(&open_disc_mutex);
 
 
 	/* grab a power reference */
 	/* grab a power reference */
 	r = usb_autopm_get_interface(interface);
 	r = usb_autopm_get_interface(interface);
@@ -393,8 +400,10 @@ static void lcd_disconnect(struct usb_interface *interface)
 	struct usb_lcd *dev;
 	struct usb_lcd *dev;
         int minor = interface->minor;
         int minor = interface->minor;
 
 
+	mutex_lock(&open_disc_mutex);
         dev = usb_get_intfdata(interface);
         dev = usb_get_intfdata(interface);
         usb_set_intfdata(interface, NULL);
         usb_set_intfdata(interface, NULL);
+	mutex_unlock(&open_disc_mutex);
 
 
         /* give back our minor */
         /* give back our minor */
         usb_deregister_dev(interface, &lcd_class);
         usb_deregister_dev(interface, &lcd_class);