aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2012-09-12 07:48:31 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-12 13:00:51 -0400
commit1f2235b8e79bd276f19809f7f2a270f55909d695 (patch)
tree98c25c71a5db781442af70ae350d904b232dd159 /drivers/usb/core
parent58efc77c86af5cb81d7d7ea0c3c3e675e7d121dc (diff)
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>
Diffstat (limited to 'drivers/usb/core')
-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)
1584 struct usb_device *hdev = interface_to_usbdev(intf); 1584 struct usb_device *hdev = interface_to_usbdev(intf);
1585 int i; 1585 int i;
1586 1586
1587 for (i = 0; i < hdev->maxchild; i++)
1588 usb_hub_remove_port_device(hub, i + 1);
1589
1590 /* Take the hub off the event list and don't let it be added again */ 1587 /* Take the hub off the event list and don't let it be added again */
1591 spin_lock_irq(&hub_event_lock); 1588 spin_lock_irq(&hub_event_lock);
1592 if (!list_empty(&hub->event_list)) { 1589 if (!list_empty(&hub->event_list)) {
@@ -1601,6 +1598,9 @@ static void hub_disconnect(struct usb_interface *intf)
1601 hub_quiesce(hub, HUB_DISCONNECT); 1598 hub_quiesce(hub, HUB_DISCONNECT);
1602 1599
1603 usb_set_intfdata (intf, NULL); 1600 usb_set_intfdata (intf, NULL);
1601
1602 for (i = 0; i < hdev->maxchild; i++)
1603 usb_hub_remove_port_device(hub, i + 1);
1604 hub->hdev->maxchild = 0; 1604 hub->hdev->maxchild = 0;
1605 1605
1606 if (hub->hdev->speed == USB_SPEED_HIGH) 1606 if (hub->hdev->speed == USB_SPEED_HIGH)