aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2015-01-28 05:14:55 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-31 11:58:38 -0500
commit7e860a6e7aa62b337a61110430cd633db5b0d2dd (patch)
treee5a3d99cb5cd1f66edbffd7eef694588cbcdce0d
parent6b629f2826419ab0fde54d04d97531fe4ce972bf (diff)
cdc-acm: add sanity checks
Check the special CDC headers for a plausible minimum length. Another big operating systems ignores such garbage. Signed-off-by: Oliver Neukum <oneukum@suse.de> CC: stable@vger.kernel.org Reviewed-by: Adam Lee <adam8157@gmail.com> Tested-by: Adam Lee <adam8157@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/class/cdc-acm.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 546a17e8ad5b..a417b738824f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1091,6 +1091,7 @@ static int acm_probe(struct usb_interface *intf,
1091 unsigned long quirks; 1091 unsigned long quirks;
1092 int num_rx_buf; 1092 int num_rx_buf;
1093 int i; 1093 int i;
1094 unsigned int elength = 0;
1094 int combined_interfaces = 0; 1095 int combined_interfaces = 0;
1095 struct device *tty_dev; 1096 struct device *tty_dev;
1096 int rv = -ENOMEM; 1097 int rv = -ENOMEM;
@@ -1136,9 +1137,12 @@ static int acm_probe(struct usb_interface *intf,
1136 dev_err(&intf->dev, "skipping garbage\n"); 1137 dev_err(&intf->dev, "skipping garbage\n");
1137 goto next_desc; 1138 goto next_desc;
1138 } 1139 }
1140 elength = buffer[0];
1139 1141
1140 switch (buffer[2]) { 1142 switch (buffer[2]) {
1141 case USB_CDC_UNION_TYPE: /* we've found it */ 1143 case USB_CDC_UNION_TYPE: /* we've found it */
1144 if (elength < sizeof(struct usb_cdc_union_desc))
1145 goto next_desc;
1142 if (union_header) { 1146 if (union_header) {
1143 dev_err(&intf->dev, "More than one " 1147 dev_err(&intf->dev, "More than one "
1144 "union descriptor, skipping ...\n"); 1148 "union descriptor, skipping ...\n");
@@ -1147,29 +1151,36 @@ static int acm_probe(struct usb_interface *intf,
1147 union_header = (struct usb_cdc_union_desc *)buffer; 1151 union_header = (struct usb_cdc_union_desc *)buffer;
1148 break; 1152 break;
1149 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ 1153 case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
1154 if (elength < sizeof(struct usb_cdc_country_functional_desc))
1155 goto next_desc;
1150 cfd = (struct usb_cdc_country_functional_desc *)buffer; 1156 cfd = (struct usb_cdc_country_functional_desc *)buffer;
1151 break; 1157 break;
1152 case USB_CDC_HEADER_TYPE: /* maybe check version */ 1158 case USB_CDC_HEADER_TYPE: /* maybe check version */
1153 break; /* for now we ignore it */ 1159 break; /* for now we ignore it */
1154 case USB_CDC_ACM_TYPE: 1160 case USB_CDC_ACM_TYPE:
1161 if (elength < 4)
1162 goto next_desc;
1155 ac_management_function = buffer[3]; 1163 ac_management_function = buffer[3];
1156 break; 1164 break;
1157 case USB_CDC_CALL_MANAGEMENT_TYPE: 1165 case USB_CDC_CALL_MANAGEMENT_TYPE:
1166 if (elength < 5)
1167 goto next_desc;
1158 call_management_function = buffer[3]; 1168 call_management_function = buffer[3];
1159 call_interface_num = buffer[4]; 1169 call_interface_num = buffer[4];
1160 break; 1170 break;
1161 default: 1171 default:
1162 /* there are LOTS more CDC descriptors that 1172 /*
1173 * there are LOTS more CDC descriptors that
1163 * could legitimately be found here. 1174 * could legitimately be found here.
1164 */ 1175 */
1165 dev_dbg(&intf->dev, "Ignoring descriptor: " 1176 dev_dbg(&intf->dev, "Ignoring descriptor: "
1166 "type %02x, length %d\n", 1177 "type %02x, length %ud\n",
1167 buffer[2], buffer[0]); 1178 buffer[2], elength);
1168 break; 1179 break;
1169 } 1180 }
1170next_desc: 1181next_desc:
1171 buflen -= buffer[0]; 1182 buflen -= elength;
1172 buffer += buffer[0]; 1183 buffer += elength;
1173 } 1184 }
1174 1185
1175 if (!union_header) { 1186 if (!union_header) {