summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2012-09-12 14:48:31 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-12 10:00:51 -0700
commit1f2235b8e79bd276f19809f7f2a270f55909d695 (patch)
tree98c25c71a5db781442af70ae350d904b232dd159
parent58efc77c86af5cb81d7d7ea0c3c3e675e7d121dc (diff)
downloadlinux-1f2235b8e79bd276f19809f7f2a270f55909d695.tar.gz
linux-1f2235b8e79bd276f19809f7f2a270f55909d695.tar.bz2
linux-1f2235b8e79bd276f19809f7f2a270f55909d695.zip
usb: move children deallocation after quiescing the hub
Commit ff823c79a5c33194c2e5594f7c4686ea3547910c ("usb: move children to struct usb_port") forgot to consider the hub_disconnect sequence, which releases ports before quiescing the hub, which will lead to a use-after-free, since hub_quiesce() will try to disconnect ports' children, which are already deallocated. Simple modprobe dummy_hcd && rmmod dummy_hcd will illustrate the problem. This patch moves deallocation of hub's ports after hub_quiesce() call in hub_disconnect(). Cc: Lan Tianyu <tianyu.lan@intel.com> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/core/hub.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index aa45e43e0ca9..6dc41c6399de 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1584,9 +1584,6 @@ static void hub_disconnect(struct usb_interface *intf)
struct usb_device *hdev = interface_to_usbdev(intf);
int i;
- for (i = 0; i < hdev->maxchild; i++)
- usb_hub_remove_port_device(hub, i + 1);
-
/* Take the hub off the event list and don't let it be added again */
spin_lock_irq(&hub_event_lock);
if (!list_empty(&hub->event_list)) {
@@ -1601,6 +1598,9 @@ static void hub_disconnect(struct usb_interface *intf)
hub_quiesce(hub, HUB_DISCONNECT);
usb_set_intfdata (intf, NULL);
+
+ for (i = 0; i < hdev->maxchild; i++)
+ usb_hub_remove_port_device(hub, i + 1);
hub->hdev->maxchild = 0;
if (hub->hdev->speed == USB_SPEED_HIGH)