cdc-acm: add sanity checks
[pandora-kernel.git] / drivers / usb / class / cdc-acm.c
index d38d88e..360ddb5 100644 (file)
@@ -911,6 +911,7 @@ static int acm_probe(struct usb_interface *intf,
        unsigned long quirks;
        int num_rx_buf;
        int i;
+       unsigned int elength = 0;
        int combined_interfaces = 0;
 
        /* normal quirks */
@@ -950,9 +951,12 @@ static int acm_probe(struct usb_interface *intf,
                        dev_err(&intf->dev, "skipping garbage\n");
                        goto next_desc;
                }
+               elength = buffer[0];
 
                switch (buffer[2]) {
                case USB_CDC_UNION_TYPE: /* we've found it */
+                       if (elength < sizeof(struct usb_cdc_union_desc))
+                               goto next_desc;
                        if (union_header) {
                                dev_err(&intf->dev, "More than one "
                                        "union descriptor, skipping ...\n");
@@ -961,31 +965,38 @@ static int acm_probe(struct usb_interface *intf,
                        union_header = (struct usb_cdc_union_desc *)buffer;
                        break;
                case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
+                       if (elength < sizeof(struct usb_cdc_country_functional_desc))
+                               goto next_desc;
                        cfd = (struct usb_cdc_country_functional_desc *)buffer;
                        break;
                case USB_CDC_HEADER_TYPE: /* maybe check version */
                        break; /* for now we ignore it */
                case USB_CDC_ACM_TYPE:
+                       if (elength < 4)
+                               goto next_desc;
                        ac_management_function = buffer[3];
                        break;
                case USB_CDC_CALL_MANAGEMENT_TYPE:
+                       if (elength < 5)
+                               goto next_desc;
                        call_management_function = buffer[3];
                        call_interface_num = buffer[4];
                        if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
                                dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
                        break;
                default:
-                       /* there are LOTS more CDC descriptors that
+                       /*
+                        * there are LOTS more CDC descriptors that
                         * could legitimately be found here.
                         */
                        dev_dbg(&intf->dev, "Ignoring descriptor: "
-                                       "type %02x, length %d\n",
-                                       buffer[2], buffer[0]);
+                                       "type %02x, length %ud\n",
+                                       buffer[2], elength);
                        break;
                }
 next_desc:
-               buflen -= buffer[0];
-               buffer += buffer[0];
+               buflen -= elength;
+               buffer += elength;
        }
 
        if (!union_header) {