summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2016-09-18 09:51:25 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2016-09-18 09:51:25 +0000
commit407411547fd928dbd463c15caa8b04ccba3ef83d (patch)
tree16ac93bb896e47e8da22f09b60f8eff8bc79238e /sys/dev
parent293b01f93daf79742cab224c0b701b2f7b635b39 (diff)
Ensure that the device descriptor ``bMaxPacketSize'' value is usable
before using it as the ``wMaxPacketSize'' of the default endpoint. This prevents host controller drivers from using incorrect value, in particular 0, that makes ehci(4) crash. While here do the 0xff -> 512 conversion for super speed devices. Crash found with a facedancer21. ok deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/usb_subr.c67
1 files changed, 41 insertions, 26 deletions
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index e65af73c514..5b5a14fd119 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_subr.c,v 1.128 2016/09/12 07:43:10 mpi Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.129 2016/09/18 09:51:24 mpi Exp $ */
/* $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
@@ -1023,16 +1023,34 @@ usbd_status
usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth,
int speed, int port, struct usbd_port *up)
{
- struct usbd_device *dev, *adev;
- struct usbd_device *hub;
+ struct usbd_device *dev, *adev, *hub;
usb_device_descriptor_t *dd;
usbd_status err;
- int addr;
- int i;
- int p;
+ uint32_t mps, mps0;
+ int addr, i, p;
DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n",
bus, port, depth, speed));
+
+ /*
+ * Fixed size for ep0 max packet, FULL device variable size is
+ * handled below.
+ */
+ switch (speed) {
+ case USB_SPEED_LOW:
+ mps0 = 8;
+ break;
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ mps0 = 64;
+ break;
+ case USB_SPEED_SUPER:
+ mps0 = 512;
+ break;
+ default:
+ return (USBD_INVAL);
+ }
+
addr = usbd_getnewaddr(bus);
if (addr < 0) {
printf("%s: No free USB addresses, new device ignored.\n",
@@ -1054,8 +1072,8 @@ usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth,
dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;
dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
dev->def_ep_desc.bmAttributes = UE_CONTROL;
- USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
dev->def_ep_desc.bInterval = 0;
+ USETW(dev->def_ep_desc.wMaxPacketSize, mps0);
dev->quirks = &usbd_no_quirk;
dev->address = USB_START_ADDR;
@@ -1063,6 +1081,8 @@ usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth,
dev->depth = depth;
dev->powersrc = up;
dev->myhub = up->parent;
+ dev->speed = speed;
+ dev->langid = USBD_NOLANG;
up->device = dev;
@@ -1084,8 +1104,6 @@ usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth,
} else {
dev->myhsport = NULL;
}
- dev->speed = speed;
- dev->langid = USBD_NOLANG;
/* Establish the default pipe. */
err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
@@ -1143,36 +1161,33 @@ usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth,
return (err);
}
- if (speed == USB_SPEED_HIGH) {
- /* Max packet size must be 64 (sec 5.5.3). */
- if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) {
-#ifdef DIAGNOSTIC
- printf("%s: addr=%d bad max packet size %d\n", __func__,
- addr, dd->bMaxPacketSize);
-#endif
- dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET;
- }
- }
-
DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
"subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n",
addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,
dev->speed));
- if (dd->bDescriptorType != UDESC_DEVICE) {
+ if ((dd->bDescriptorType != UDESC_DEVICE) ||
+ (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE)) {
usb_free_device(dev);
up->device = NULL;
return (USBD_INVAL);
}
- if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) {
- usb_free_device(dev);
- up->device = NULL;
- return (USBD_INVAL);
+ mps = dd->bMaxPacketSize;
+ if (speed == USB_SPEED_SUPER && mps == 0xff)
+ mps = 512;
+
+ if (mps != mps0) {
+ if ((speed == USB_SPEED_LOW) ||
+ (mps != 8 || mps != 16 || mps != 32 || mps != 64)) {
+ usb_free_device(dev);
+ up->device = NULL;
+ return (USBD_INVAL);
+ }
+ USETW(dev->def_ep_desc.wMaxPacketSize, mps);
}
- USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);
/* Set the address if the HC didn't do it already. */
if (bus->methods->dev_setaddr != NULL &&