aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2013-07-24 13:27:13 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-04 04:50:46 -0400
commit5dbb5d4f24bf6862a888637b7506d1e04c2d2276 (patch)
treee60959ef2fde5f93ca6ed688e908d0a485d34073
parent10a1c13241f682cdc866f2aa8a0e5c5373470ecb (diff)
xhci: Avoid NULL pointer deref when host dies.
commit 203a86613fb3bf2767335659513fa98563a3eb71 upstream. When the host controller fails to respond to an Enable Slot command, and the host fails to respond to the register write to abort the command ring, the xHCI driver will assume the host is dead, and call usb_hc_died(). The USB device's slot_id is still set to zero, and the pointer stored at xhci->devs[0] will always be NULL. The call to xhci_check_args in xhci_free_dev should have caught the NULL virt_dev pointer. However, xhci_free_dev is designed to free the xhci_virt_device structures, even if the host is dead, so that we don't leak kernel memory. xhci_free_dev checks the return value from the generic xhci_check_args function. If the return value is -ENODEV, it carries on trying to free the virtual device. The issue is that xhci_check_args looks at the host controller state before it looks at the xhci_virt_device pointer. It will return -ENIVAL because the host is dead, and xhci_free_dev will ignore the return value, and happily dereference the NULL xhci_virt_device pointer. The fix is to make sure that xhci_check_args checks the xhci_virt_device pointer before it checks the host state. See https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1203453 for further details. This patch doesn't solve the underlying issue, but will ensure we don't see any more NULL pointer dereferences because of the issue. This patch should be backported to kernels as old as 3.1, that contain the commit 7bd89b4017f46a9b92853940fd9771319acb578a "xhci: Don't submit commands or URBs to halted hosts." Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Reported-by: Vincent Thiele <vincentthiele@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/xhci.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0f7be59d5319..9a550b6ad01d 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1171,9 +1171,6 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
1171 } 1171 }
1172 1172
1173 xhci = hcd_to_xhci(hcd); 1173 xhci = hcd_to_xhci(hcd);
1174 if (xhci->xhc_state & XHCI_STATE_HALTED)
1175 return -ENODEV;
1176
1177 if (check_virt_dev) { 1174 if (check_virt_dev) {
1178 if (!udev->slot_id || !xhci->devs[udev->slot_id]) { 1175 if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
1179 printk(KERN_DEBUG "xHCI %s called with unaddressed " 1176 printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1189,6 +1186,9 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
1189 } 1186 }
1190 } 1187 }
1191 1188
1189 if (xhci->xhc_state & XHCI_STATE_HALTED)
1190 return -ENODEV;
1191
1192 return 1; 1192 return 1;
1193} 1193}
1194 1194