diff options
author | Oliver Neukum <oliver@neukum.org> | 2007-10-25 15:48:39 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-25 12:18:46 -0700 |
commit | 78663ecc344b4694dd737deb682e81312a0684b6 (patch) | |
tree | 297a7130b13f471d5d6fa936c20cf772632fb446 | |
parent | 03f36e885fc26cb0ea299fb6df5171a51e814548 (diff) | |
download | linux-78663ecc344b4694dd737deb682e81312a0684b6.tar.gz linux-78663ecc344b4694dd737deb682e81312a0684b6.tar.bz2 linux-78663ecc344b4694dd737deb682e81312a0684b6.zip |
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.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 [] = { }; MODULE_DEVICE_TABLE (usb, tower_table); +static DEFINE_MUTEX(open_disc_mutex); #define LEGO_USB_TOWER_MINOR_BASE 160 @@ -350,25 +351,31 @@ static int tower_open (struct inode *inode, struct file *file) goto exit; } + mutex_lock(&open_disc_mutex); dev = usb_get_intfdata(interface); if (!dev) { + mutex_unlock(&open_disc_mutex); retval = -ENODEV; goto exit; } /* lock this device */ if (down_interruptible (&dev->sem)) { + mutex_unlock(&open_disc_mutex); retval = -ERESTARTSYS; goto exit; } + /* allow opening only once */ if (dev->open_count) { + mutex_unlock(&open_disc_mutex); retval = -EBUSY; goto unlock_exit; } dev->open_count = 1; + mutex_unlock(&open_disc_mutex); /* reset the tower */ result = usb_control_msg (dev->udev, @@ -437,9 +444,10 @@ static int tower_release (struct inode *inode, struct file *file) if (dev == NULL) { dbg(1, "%s: object is NULL", __FUNCTION__); retval = -ENODEV; - goto exit; + goto exit_nolock; } + mutex_lock(&open_disc_mutex); if (down_interruptible (&dev->sem)) { retval = -ERESTARTSYS; goto exit; @@ -468,6 +476,8 @@ unlock_exit: up (&dev->sem); exit: + mutex_unlock(&open_disc_mutex); +exit_nolock: dbg(2, "%s: leave, return value %d", __FUNCTION__, retval); return retval; } @@ -989,6 +999,7 @@ static void tower_disconnect (struct usb_interface *interface) dbg(2, "%s: enter", __FUNCTION__); dev = usb_get_intfdata (interface); + mutex_lock(&open_disc_mutex); usb_set_intfdata (interface, NULL); minor = dev->minor; @@ -997,6 +1008,7 @@ static void tower_disconnect (struct usb_interface *interface) usb_deregister_dev (interface, &tower_class); down (&dev->sem); + mutex_unlock(&open_disc_mutex); /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { |