diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2016-08-01 15:25:56 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-08-09 10:14:18 -0400 |
| commit | aed9d65ac3278d4febd8665bd7db59ef53e825fe (patch) | |
| tree | f9a3decc5f7b42dc3b12e34b3fac1c20c3cbe713 /drivers/usb/core | |
| parent | 9c6256a5e707a9eb8b91962b550050b13aa75334 (diff) | |
USB: validate wMaxPacketValue entries in endpoint descriptors
Erroneous or malicious endpoint descriptors may have non-zero bits in
reserved positions, or out-of-bounds values. This patch helps prevent
these from causing problems by bounds-checking the wMaxPacketValue
entries in endpoint descriptors and capping the values at the maximum
allowed.
This issue was first discovered and tests were conducted by Jake Lamberson
<jake.lamberson1@gmail.com>, an intern working for Rosie Hall.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-by: roswest <roswest@cisco.com>
Tested-by: roswest <roswest@cisco.com>
CC: <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/config.c | 66 |
1 files changed, 63 insertions, 3 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 31ccdccd7a04..051163189810 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c | |||
| @@ -171,6 +171,31 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, | |||
| 171 | ep, buffer, size); | 171 | ep, buffer, size); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static const unsigned short low_speed_maxpacket_maxes[4] = { | ||
| 175 | [USB_ENDPOINT_XFER_CONTROL] = 8, | ||
| 176 | [USB_ENDPOINT_XFER_ISOC] = 0, | ||
| 177 | [USB_ENDPOINT_XFER_BULK] = 0, | ||
| 178 | [USB_ENDPOINT_XFER_INT] = 8, | ||
| 179 | }; | ||
| 180 | static const unsigned short full_speed_maxpacket_maxes[4] = { | ||
| 181 | [USB_ENDPOINT_XFER_CONTROL] = 64, | ||
| 182 | [USB_ENDPOINT_XFER_ISOC] = 1023, | ||
| 183 | [USB_ENDPOINT_XFER_BULK] = 64, | ||
| 184 | [USB_ENDPOINT_XFER_INT] = 64, | ||
| 185 | }; | ||
| 186 | static const unsigned short high_speed_maxpacket_maxes[4] = { | ||
| 187 | [USB_ENDPOINT_XFER_CONTROL] = 64, | ||
| 188 | [USB_ENDPOINT_XFER_ISOC] = 1024, | ||
| 189 | [USB_ENDPOINT_XFER_BULK] = 512, | ||
| 190 | [USB_ENDPOINT_XFER_INT] = 1023, | ||
| 191 | }; | ||
| 192 | static const unsigned short super_speed_maxpacket_maxes[4] = { | ||
| 193 | [USB_ENDPOINT_XFER_CONTROL] = 512, | ||
| 194 | [USB_ENDPOINT_XFER_ISOC] = 1024, | ||
| 195 | [USB_ENDPOINT_XFER_BULK] = 1024, | ||
| 196 | [USB_ENDPOINT_XFER_INT] = 1024, | ||
| 197 | }; | ||
| 198 | |||
| 174 | static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | 199 | static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, |
| 175 | int asnum, struct usb_host_interface *ifp, int num_ep, | 200 | int asnum, struct usb_host_interface *ifp, int num_ep, |
| 176 | unsigned char *buffer, int size) | 201 | unsigned char *buffer, int size) |
| @@ -179,6 +204,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | |||
| 179 | struct usb_endpoint_descriptor *d; | 204 | struct usb_endpoint_descriptor *d; |
| 180 | struct usb_host_endpoint *endpoint; | 205 | struct usb_host_endpoint *endpoint; |
| 181 | int n, i, j, retval; | 206 | int n, i, j, retval; |
| 207 | unsigned int maxp; | ||
| 208 | const unsigned short *maxpacket_maxes; | ||
| 182 | 209 | ||
| 183 | d = (struct usb_endpoint_descriptor *) buffer; | 210 | d = (struct usb_endpoint_descriptor *) buffer; |
| 184 | buffer += d->bLength; | 211 | buffer += d->bLength; |
| @@ -286,6 +313,42 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | |||
| 286 | endpoint->desc.wMaxPacketSize = cpu_to_le16(8); | 313 | endpoint->desc.wMaxPacketSize = cpu_to_le16(8); |
| 287 | } | 314 | } |
| 288 | 315 | ||
| 316 | /* Validate the wMaxPacketSize field */ | ||
| 317 | maxp = usb_endpoint_maxp(&endpoint->desc); | ||
| 318 | |||
| 319 | /* Find the highest legal maxpacket size for this endpoint */ | ||
| 320 | i = 0; /* additional transactions per microframe */ | ||
| 321 | switch (to_usb_device(ddev)->speed) { | ||
| 322 | case USB_SPEED_LOW: | ||
| 323 | maxpacket_maxes = low_speed_maxpacket_maxes; | ||
| 324 | break; | ||
| 325 | case USB_SPEED_FULL: | ||
| 326 | maxpacket_maxes = full_speed_maxpacket_maxes; | ||
| 327 | break; | ||
| 328 | case USB_SPEED_HIGH: | ||
| 329 | /* Bits 12..11 are allowed only for HS periodic endpoints */ | ||
| 330 | if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) { | ||
| 331 | i = maxp & (BIT(12) | BIT(11)); | ||
| 332 | maxp &= ~i; | ||
| 333 | } | ||
| 334 | /* fallthrough */ | ||
| 335 | default: | ||
| 336 | maxpacket_maxes = high_speed_maxpacket_maxes; | ||
| 337 | break; | ||
| 338 | case USB_SPEED_SUPER: | ||
| 339 | case USB_SPEED_SUPER_PLUS: | ||
| 340 | maxpacket_maxes = super_speed_maxpacket_maxes; | ||
| 341 | break; | ||
| 342 | } | ||
| 343 | j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)]; | ||
| 344 | |||
| 345 | if (maxp > j) { | ||
| 346 | dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n", | ||
| 347 | cfgno, inum, asnum, d->bEndpointAddress, maxp, j); | ||
| 348 | maxp = j; | ||
| 349 | endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp); | ||
| 350 | } | ||
| 351 | |||
| 289 | /* | 352 | /* |
| 290 | * Some buggy high speed devices have bulk endpoints using | 353 | * Some buggy high speed devices have bulk endpoints using |
| 291 | * maxpacket sizes other than 512. High speed HCDs may not | 354 | * maxpacket sizes other than 512. High speed HCDs may not |
| @@ -293,9 +356,6 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, | |||
| 293 | */ | 356 | */ |
| 294 | if (to_usb_device(ddev)->speed == USB_SPEED_HIGH | 357 | if (to_usb_device(ddev)->speed == USB_SPEED_HIGH |
| 295 | && usb_endpoint_xfer_bulk(d)) { | 358 | && usb_endpoint_xfer_bulk(d)) { |
| 296 | unsigned maxp; | ||
| 297 | |||
| 298 | maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff; | ||
| 299 | if (maxp != 512) | 359 | if (maxp != 512) |
| 300 | dev_warn(ddev, "config %d interface %d altsetting %d " | 360 | dev_warn(ddev, "config %d interface %d altsetting %d " |
| 301 | "bulk endpoint 0x%X has invalid maxpacket %d\n", | 361 | "bulk endpoint 0x%X has invalid maxpacket %d\n", |
