diff options
author | Oliver Neukum <oneukum@suse.de> | 2015-01-28 05:14:55 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-01-31 11:58:38 -0500 |
commit | 7e860a6e7aa62b337a61110430cd633db5b0d2dd (patch) | |
tree | e5a3d99cb5cd1f66edbffd7eef694588cbcdce0d | |
parent | 6b629f2826419ab0fde54d04d97531fe4ce972bf (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.c | 21 |
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 | } |
1170 | next_desc: | 1181 | next_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) { |