From 26c71a79cade5ccad80e0752cd82f3518df48fb3 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 16 Dec 2011 22:20:01 +0800 Subject: USB: usb-skeleton.c: fix open/disconnect race If usb device is disconnected between usb_get_intfdata() and kref_get() in skel_open(), kref_get may access a freed object. Also check if device is disconnected in ->open. Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/usb/usb-skeleton.c') diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 32d6fc953904..3635f9e37559 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -27,6 +27,8 @@ #define USB_SKEL_VENDOR_ID 0xfff0 #define USB_SKEL_PRODUCT_ID 0xfff0 +static DEFINE_MUTEX(skel_mutex); + /* table of devices that work with this driver */ static const struct usb_device_id skel_table[] = { { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, @@ -100,18 +102,25 @@ static int skel_open(struct inode *inode, struct file *file) goto exit; } + mutex_lock(&skel_mutex); dev = usb_get_intfdata(interface); if (!dev) { + mutex_unlock(&skel_mutex); retval = -ENODEV; goto exit; } /* increment our usage count for the device */ kref_get(&dev->kref); + mutex_unlock(&skel_mutex); /* lock the device to allow correctly handling errors * in resumption */ mutex_lock(&dev->io_mutex); + if (!dev->interface) { + retval = -ENODEV; + goto out_err; + } if (!dev->open_count++) { retval = usb_autopm_get_interface(interface); @@ -132,7 +141,11 @@ static int skel_open(struct inode *inode, struct file *file) /* save our object in the file's private structure */ file->private_data = dev; + +out_err: mutex_unlock(&dev->io_mutex); + if (retval) + kref_put(&dev->kref, skel_delete); exit: return retval; @@ -612,7 +625,6 @@ static void skel_disconnect(struct usb_interface *interface) int minor = interface->minor; dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); /* give back our minor */ usb_deregister_dev(interface, &skel_class); @@ -624,8 +636,12 @@ static void skel_disconnect(struct usb_interface *interface) usb_kill_anchored_urbs(&dev->submitted); + mutex_lock(&skel_mutex); + usb_set_intfdata(interface, NULL); + /* decrement our usage count */ kref_put(&dev->kref, skel_delete); + mutex_unlock(&skel_mutex); dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor); } -- cgit v1.2.3 From e28dbb0661ca49ada2d6a307a1ec93dd75d515e0 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 16 Dec 2011 22:20:44 +0800 Subject: USB: usb-skeleton.c: cleanup open_count It is not necessary to use the 'open_count' for handling runtime pm only, because runtinme pm has built-in counter to handle this, so remove it to make code clean. Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'drivers/usb/usb-skeleton.c') diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 3635f9e37559..d9a95847ec1f 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -62,7 +62,6 @@ struct usb_skel { __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ int errors; /* the last request tanked */ - int open_count; /* count the number of openers */ bool ongoing_read; /* a read is going on */ bool processed_urb; /* indicates we haven't processed the urb */ spinlock_t err_lock; /* lock for errors */ @@ -122,22 +121,9 @@ static int skel_open(struct inode *inode, struct file *file) goto out_err; } - if (!dev->open_count++) { - retval = usb_autopm_get_interface(interface); - if (retval) { - dev->open_count--; - mutex_unlock(&dev->io_mutex); - kref_put(&dev->kref, skel_delete); - goto exit; - } - } /* else { //uncomment this block if you want exclusive open - retval = -EBUSY; - dev->open_count--; - mutex_unlock(&dev->io_mutex); - kref_put(&dev->kref, skel_delete); - goto exit; - } */ - /* prevent the device from being autosuspended */ + retval = usb_autopm_get_interface(interface); + if (retval) + goto out_err; /* save our object in the file's private structure */ file->private_data = dev; @@ -161,7 +147,7 @@ static int skel_release(struct inode *inode, struct file *file) /* allow the device to be autosuspended */ mutex_lock(&dev->io_mutex); - if (!--dev->open_count && dev->interface) + if (dev->interface) usb_autopm_put_interface(dev->interface); mutex_unlock(&dev->io_mutex); -- cgit v1.2.3