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:
parent
0b61fa0fee
commit
f2fe8a544b
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue