BACKPORT: USB: core: harden cdc_parse_cdc_header

Andrey Konovalov reported a possible out-of-bounds problem for the
cdc_parse_cdc_header function.  He writes:
	It looks like cdc_parse_cdc_header() doesn't validate buflen
	before accessing buffer[1], buffer[2] and so on. The only check
	present is while (buflen > 0).

So fix this issue up by properly validating the buffer length matches
what the descriptor says it is.

(cherry picked from commit 2e1c42391ff2556387b3cb6308b24f6f65619feb)

(The original patch fixed the generic cdc_parser_cdc_header function.
That generic function did not exist in 3.10 but there are a couple
cdc parsers that suffer from the same underlying problem.)

Bug: 69052594
Change-Id: I75b16a1eaad8a06bd9ef1db66148f72e965a341f
Reported-by: Andrey Konovalov <andreyknvl@google.com>
Tested-by: Andrey Konovalov <andreyknvl@google.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Marissa Wall <marissaw@google.com>
This commit is contained in:
Marissa Wall 2017-11-16 14:32:40 -08:00 committed by syphyr
parent 0b61fa0fee
commit f2fe8a544b
5 changed files with 26 additions and 10 deletions

View File

@ -343,9 +343,9 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
data = intf->altsetting->extra;
len = intf->altsetting->extralen;
while (len >= 3) {
while (len > 0) {
u8 dlen = data[0];
if (dlen < 3)
if ((len < dlen) || (dlen < 3 ))
return -EINVAL;
/* bDescriptorType */

View File

@ -127,7 +127,13 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
memset(info, 0, sizeof(*info));
info->control = intf;
while (len > 3) {
while (len > 0) {
if ((len < buf[0]) || (buf[0] < 3)) {
dev_dbg(&intf->dev, "invalid descriptor buffer length\n");
goto bad_desc;
}
if (buf[1] != USB_DT_CS_INTERFACE)
goto next_desc;

View File

@ -235,9 +235,14 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
info->data = intf;
/* and a number of CDC descriptors */
while (len > 3) {
while (len > 0) {
struct usb_descriptor_header *h = (void *)buf;
if ((len < buf[0]) || (buf[0] < 3)) {
dev_dbg(&intf->dev, "invalid descriptor buffer length\n");
goto err;
}
/* ignore any misplaced descriptors */
if (h->bDescriptorType != USB_DT_CS_INTERFACE)
goto next_desc;

View File

@ -1043,13 +1043,13 @@ static int acm_probe(struct usb_interface *intf,
}
}
while (buflen >= 3) { /* minimum length making sense */
while (buflen > 0) {
elength = buffer[0];
if (!elength) {
dev_err(&intf->dev, "skipping garbage byte\n");
elength = 1;
goto next_desc;
if ((buflen < buffer[0]) || (buffer[0] < 3)) {
dev_err(&intf->dev, "invalid descriptor buffer length\n");
break;
}
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;

View File

@ -841,7 +841,12 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (!buffer)
goto err;
while (buflen > 2) {
while (buflen > 0) {
if ((buflen < buffer[0]) || (buffer[0] < 3)) {
dev_err(&intf->dev, "invalid descriptor buffer length\n");
goto err;
}
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;