diff options
author | Alexander Shishkin <alexander.shishkin@linux.intel.com> | 2012-09-12 14:48:31 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-09-12 10:00:51 -0700 |
commit | 1f2235b8e79bd276f19809f7f2a270f55909d695 (patch) | |
tree | 98c25c71a5db781442af70ae350d904b232dd159 | |
parent | 58efc77c86af5cb81d7d7ea0c3c3e675e7d121dc (diff) | |
download | linux-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.c | 6 |
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) |