diff options
author | Oliver Neukum <oliver@neukum.org> | 2007-10-25 09:48:39 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-25 15:18:46 -0400 |
commit | 78663ecc344b4694dd737deb682e81312a0684b6 (patch) | |
tree | 297a7130b13f471d5d6fa936c20cf772632fb446 /drivers/usb | |
parent | 03f36e885fc26cb0ea299fb6df5171a51e814548 (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>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/misc/legousbtower.c | 14 |
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 | ||
200 | MODULE_DEVICE_TABLE (usb, tower_table); | 200 | MODULE_DEVICE_TABLE (usb, tower_table); |
201 | static 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 | ||
470 | exit: | 478 | exit: |
479 | mutex_unlock(&open_disc_mutex); | ||
480 | exit_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) { |