aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2007-10-25 09:48:39 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-25 15:18:46 -0400
commit78663ecc344b4694dd737deb682e81312a0684b6 (patch)
tree297a7130b13f471d5d6fa936c20cf772632fb446
parent03f36e885fc26cb0ea299fb6df5171a51e814548 (diff)
USB: disconnect open race in legousbtower
again, possible use after free due to touching intfdata without lock. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/misc/legousbtower.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 561970b889a5..aab320085ebf 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -198,6 +198,7 @@ static struct usb_device_id tower_table [] = {
198}; 198};
199 199
200MODULE_DEVICE_TABLE (usb, tower_table); 200MODULE_DEVICE_TABLE (usb, tower_table);
201static DEFINE_MUTEX(open_disc_mutex);
201 202
202#define LEGO_USB_TOWER_MINOR_BASE 160 203#define LEGO_USB_TOWER_MINOR_BASE 160
203 204
@@ -350,25 +351,31 @@ static int tower_open (struct inode *inode, struct file *file)
350 goto exit; 351 goto exit;
351 } 352 }
352 353
354 mutex_lock(&open_disc_mutex);
353 dev = usb_get_intfdata(interface); 355 dev = usb_get_intfdata(interface);
354 356
355 if (!dev) { 357 if (!dev) {
358 mutex_unlock(&open_disc_mutex);
356 retval = -ENODEV; 359 retval = -ENODEV;
357 goto exit; 360 goto exit;
358 } 361 }
359 362
360 /* lock this device */ 363 /* lock this device */
361 if (down_interruptible (&dev->sem)) { 364 if (down_interruptible (&dev->sem)) {
365 mutex_unlock(&open_disc_mutex);
362 retval = -ERESTARTSYS; 366 retval = -ERESTARTSYS;
363 goto exit; 367 goto exit;
364 } 368 }
365 369
370
366 /* allow opening only once */ 371 /* allow opening only once */
367 if (dev->open_count) { 372 if (dev->open_count) {
373 mutex_unlock(&open_disc_mutex);
368 retval = -EBUSY; 374 retval = -EBUSY;
369 goto unlock_exit; 375 goto unlock_exit;
370 } 376 }
371 dev->open_count = 1; 377 dev->open_count = 1;
378 mutex_unlock(&open_disc_mutex);
372 379
373 /* reset the tower */ 380 /* reset the tower */
374 result = usb_control_msg (dev->udev, 381 result = usb_control_msg (dev->udev,
@@ -437,9 +444,10 @@ static int tower_release (struct inode *inode, struct file *file)
437 if (dev == NULL) { 444 if (dev == NULL) {
438 dbg(1, "%s: object is NULL", __FUNCTION__); 445 dbg(1, "%s: object is NULL", __FUNCTION__);
439 retval = -ENODEV; 446 retval = -ENODEV;
440 goto exit; 447 goto exit_nolock;
441 } 448 }
442 449
450 mutex_lock(&open_disc_mutex);
443 if (down_interruptible (&dev->sem)) { 451 if (down_interruptible (&dev->sem)) {
444 retval = -ERESTARTSYS; 452 retval = -ERESTARTSYS;
445 goto exit; 453 goto exit;
@@ -468,6 +476,8 @@ unlock_exit:
468 up (&dev->sem); 476 up (&dev->sem);
469 477
470exit: 478exit:
479 mutex_unlock(&open_disc_mutex);
480exit_nolock:
471 dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); 481 dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
472 return retval; 482 return retval;
473} 483}
@@ -989,6 +999,7 @@ static void tower_disconnect (struct usb_interface *interface)
989 dbg(2, "%s: enter", __FUNCTION__); 999 dbg(2, "%s: enter", __FUNCTION__);
990 1000
991 dev = usb_get_intfdata (interface); 1001 dev = usb_get_intfdata (interface);
1002 mutex_lock(&open_disc_mutex);
992 usb_set_intfdata (interface, NULL); 1003 usb_set_intfdata (interface, NULL);
993 1004
994 minor = dev->minor; 1005 minor = dev->minor;
@@ -997,6 +1008,7 @@ static void tower_disconnect (struct usb_interface *interface)
997 usb_deregister_dev (interface, &tower_class); 1008 usb_deregister_dev (interface, &tower_class);
998 1009
999 down (&dev->sem); 1010 down (&dev->sem);
1011 mutex_unlock(&open_disc_mutex);
1000 1012
1001 /* if the device is not opened, then we clean up right now */ 1013 /* if the device is not opened, then we clean up right now */
1002 if (!dev->open_count) { 1014 if (!dev->open_count) {