forked from mirrors/linux
		
	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>
This commit is contained in:
		
							parent
							
								
									6b629f2826
								
							
						
					
					
						commit
						7e860a6e7a
					
				
					 1 changed files with 16 additions and 5 deletions
				
			
		|  | @ -1091,6 +1091,7 @@ static int acm_probe(struct usb_interface *intf, | ||||||
| 	unsigned long quirks; | 	unsigned long quirks; | ||||||
| 	int num_rx_buf; | 	int num_rx_buf; | ||||||
| 	int i; | 	int i; | ||||||
|  | 	unsigned int elength = 0; | ||||||
| 	int combined_interfaces = 0; | 	int combined_interfaces = 0; | ||||||
| 	struct device *tty_dev; | 	struct device *tty_dev; | ||||||
| 	int rv = -ENOMEM; | 	int rv = -ENOMEM; | ||||||
|  | @ -1136,9 +1137,12 @@ static int acm_probe(struct usb_interface *intf, | ||||||
| 			dev_err(&intf->dev, "skipping garbage\n"); | 			dev_err(&intf->dev, "skipping garbage\n"); | ||||||
| 			goto next_desc; | 			goto next_desc; | ||||||
| 		} | 		} | ||||||
|  | 		elength = buffer[0]; | ||||||
| 
 | 
 | ||||||
| 		switch (buffer[2]) { | 		switch (buffer[2]) { | ||||||
| 		case USB_CDC_UNION_TYPE: /* we've found it */ | 		case USB_CDC_UNION_TYPE: /* we've found it */ | ||||||
|  | 			if (elength < sizeof(struct usb_cdc_union_desc)) | ||||||
|  | 				goto next_desc; | ||||||
| 			if (union_header) { | 			if (union_header) { | ||||||
| 				dev_err(&intf->dev, "More than one " | 				dev_err(&intf->dev, "More than one " | ||||||
| 					"union descriptor, skipping ...\n"); | 					"union descriptor, skipping ...\n"); | ||||||
|  | @ -1147,29 +1151,36 @@ static int acm_probe(struct usb_interface *intf, | ||||||
| 			union_header = (struct usb_cdc_union_desc *)buffer; | 			union_header = (struct usb_cdc_union_desc *)buffer; | ||||||
| 			break; | 			break; | ||||||
| 		case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ | 		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; | 			cfd = (struct usb_cdc_country_functional_desc *)buffer; | ||||||
| 			break; | 			break; | ||||||
| 		case USB_CDC_HEADER_TYPE: /* maybe check version */ | 		case USB_CDC_HEADER_TYPE: /* maybe check version */ | ||||||
| 			break; /* for now we ignore it */ | 			break; /* for now we ignore it */ | ||||||
| 		case USB_CDC_ACM_TYPE: | 		case USB_CDC_ACM_TYPE: | ||||||
|  | 			if (elength < 4) | ||||||
|  | 				goto next_desc; | ||||||
| 			ac_management_function = buffer[3]; | 			ac_management_function = buffer[3]; | ||||||
| 			break; | 			break; | ||||||
| 		case USB_CDC_CALL_MANAGEMENT_TYPE: | 		case USB_CDC_CALL_MANAGEMENT_TYPE: | ||||||
|  | 			if (elength < 5) | ||||||
|  | 				goto next_desc; | ||||||
| 			call_management_function = buffer[3]; | 			call_management_function = buffer[3]; | ||||||
| 			call_interface_num = buffer[4]; | 			call_interface_num = buffer[4]; | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			/* there are LOTS more CDC descriptors that
 | 			/*
 | ||||||
|  | 			 * there are LOTS more CDC descriptors that | ||||||
| 			 * could legitimately be found here. | 			 * could legitimately be found here. | ||||||
| 			 */ | 			 */ | ||||||
| 			dev_dbg(&intf->dev, "Ignoring descriptor: " | 			dev_dbg(&intf->dev, "Ignoring descriptor: " | ||||||
| 					"type %02x, length %d\n", | 					"type %02x, length %ud\n", | ||||||
| 					buffer[2], buffer[0]); | 					buffer[2], elength); | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| next_desc: | next_desc: | ||||||
| 		buflen -= buffer[0]; | 		buflen -= elength; | ||||||
| 		buffer += buffer[0]; | 		buffer += elength; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!union_header) { | 	if (!union_header) { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Oliver Neukum
						Oliver Neukum