diff options
author | Bjørn Mork <bjorn@mork.no> | 2012-05-09 07:53:23 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-05-11 18:19:22 -0400 |
commit | 6286d85e8efdb59252d1ceb99a56fa6b0b11526c (patch) | |
tree | 37b91b39c74370899aedd708921f6774850cd52a /drivers/usb/class | |
parent | 6b0b79d38806481c1c8fffa7c5842f3c83679a42 (diff) |
USB: cdc-wdm: remove from device list on disconnect
Prevents dereferencing an invalid struct usb_interface
pointer.
Always delete entry from device list whether or not the
rest of the device state cleanup is postponed. The device
list uses desc->intf as key, and wdm_open will dereference
this key while searching for a matching device. A device
should not appear in the list unless probe() has succeeded
and disconnect() has not finished.
Cc: Oliver Neukum <oliver@neukum.org>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/cdc-wdm.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 90bc916d7cbd..631bb952d0f6 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
@@ -309,9 +309,6 @@ static void free_urbs(struct wdm_device *desc) | |||
309 | 309 | ||
310 | static void cleanup(struct wdm_device *desc) | 310 | static void cleanup(struct wdm_device *desc) |
311 | { | 311 | { |
312 | spin_lock(&wdm_device_list_lock); | ||
313 | list_del(&desc->device_list); | ||
314 | spin_unlock(&wdm_device_list_lock); | ||
315 | kfree(desc->sbuf); | 312 | kfree(desc->sbuf); |
316 | kfree(desc->inbuf); | 313 | kfree(desc->inbuf); |
317 | kfree(desc->orq); | 314 | kfree(desc->orq); |
@@ -782,6 +779,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor | |||
782 | out: | 779 | out: |
783 | return rv; | 780 | return rv; |
784 | err: | 781 | err: |
782 | spin_lock(&wdm_device_list_lock); | ||
783 | list_del(&desc->device_list); | ||
784 | spin_unlock(&wdm_device_list_lock); | ||
785 | cleanup(desc); | 785 | cleanup(desc); |
786 | return rv; | 786 | return rv; |
787 | } | 787 | } |
@@ -907,6 +907,12 @@ static void wdm_disconnect(struct usb_interface *intf) | |||
907 | cancel_work_sync(&desc->rxwork); | 907 | cancel_work_sync(&desc->rxwork); |
908 | mutex_unlock(&desc->wlock); | 908 | mutex_unlock(&desc->wlock); |
909 | mutex_unlock(&desc->rlock); | 909 | mutex_unlock(&desc->rlock); |
910 | |||
911 | /* the desc->intf pointer used as list key is now invalid */ | ||
912 | spin_lock(&wdm_device_list_lock); | ||
913 | list_del(&desc->device_list); | ||
914 | spin_unlock(&wdm_device_list_lock); | ||
915 | |||
910 | if (!desc->count) | 916 | if (!desc->count) |
911 | cleanup(desc); | 917 | cleanup(desc); |
912 | else | 918 | else |