forked from mirrors/linux
		
	USB: validate wMaxPacketValue entries in endpoint descriptors
Erroneous or malicious endpoint descriptors may have non-zero bits in reserved positions, or out-of-bounds values. This patch helps prevent these from causing problems by bounds-checking the wMaxPacketValue entries in endpoint descriptors and capping the values at the maximum allowed. This issue was first discovered and tests were conducted by Jake Lamberson <jake.lamberson1@gmail.com>, an intern working for Rosie Hall. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: roswest <roswest@cisco.com> Tested-by: roswest <roswest@cisco.com> CC: <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									9c6256a5e7
								
							
						
					
					
						commit
						aed9d65ac3
					
				
					 1 changed files with 63 additions and 3 deletions
				
			
		| 
						 | 
					@ -171,6 +171,31 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
 | 
				
			||||||
							ep, buffer, size);
 | 
												ep, buffer, size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const unsigned short low_speed_maxpacket_maxes[4] = {
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_CONTROL] = 8,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_ISOC] = 0,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_BULK] = 0,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_INT] = 8,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static const unsigned short full_speed_maxpacket_maxes[4] = {
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_CONTROL] = 64,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_ISOC] = 1023,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_BULK] = 64,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_INT] = 64,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static const unsigned short high_speed_maxpacket_maxes[4] = {
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_CONTROL] = 64,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_ISOC] = 1024,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_BULK] = 512,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_INT] = 1023,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static const unsigned short super_speed_maxpacket_maxes[4] = {
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_CONTROL] = 512,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_ISOC] = 1024,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_BULK] = 1024,
 | 
				
			||||||
 | 
						[USB_ENDPOINT_XFER_INT] = 1024,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 | 
					static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 | 
				
			||||||
    int asnum, struct usb_host_interface *ifp, int num_ep,
 | 
					    int asnum, struct usb_host_interface *ifp, int num_ep,
 | 
				
			||||||
    unsigned char *buffer, int size)
 | 
					    unsigned char *buffer, int size)
 | 
				
			||||||
| 
						 | 
					@ -179,6 +204,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 | 
				
			||||||
	struct usb_endpoint_descriptor *d;
 | 
						struct usb_endpoint_descriptor *d;
 | 
				
			||||||
	struct usb_host_endpoint *endpoint;
 | 
						struct usb_host_endpoint *endpoint;
 | 
				
			||||||
	int n, i, j, retval;
 | 
						int n, i, j, retval;
 | 
				
			||||||
 | 
						unsigned int maxp;
 | 
				
			||||||
 | 
						const unsigned short *maxpacket_maxes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	d = (struct usb_endpoint_descriptor *) buffer;
 | 
						d = (struct usb_endpoint_descriptor *) buffer;
 | 
				
			||||||
	buffer += d->bLength;
 | 
						buffer += d->bLength;
 | 
				
			||||||
| 
						 | 
					@ -286,6 +313,42 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 | 
				
			||||||
			endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
 | 
								endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Validate the wMaxPacketSize field */
 | 
				
			||||||
 | 
						maxp = usb_endpoint_maxp(&endpoint->desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find the highest legal maxpacket size for this endpoint */
 | 
				
			||||||
 | 
						i = 0;		/* additional transactions per microframe */
 | 
				
			||||||
 | 
						switch (to_usb_device(ddev)->speed) {
 | 
				
			||||||
 | 
						case USB_SPEED_LOW:
 | 
				
			||||||
 | 
							maxpacket_maxes = low_speed_maxpacket_maxes;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case USB_SPEED_FULL:
 | 
				
			||||||
 | 
							maxpacket_maxes = full_speed_maxpacket_maxes;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case USB_SPEED_HIGH:
 | 
				
			||||||
 | 
							/* Bits 12..11 are allowed only for HS periodic endpoints */
 | 
				
			||||||
 | 
							if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) {
 | 
				
			||||||
 | 
								i = maxp & (BIT(12) | BIT(11));
 | 
				
			||||||
 | 
								maxp &= ~i;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/* fallthrough */
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							maxpacket_maxes = high_speed_maxpacket_maxes;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case USB_SPEED_SUPER:
 | 
				
			||||||
 | 
						case USB_SPEED_SUPER_PLUS:
 | 
				
			||||||
 | 
							maxpacket_maxes = super_speed_maxpacket_maxes;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (maxp > j) {
 | 
				
			||||||
 | 
							dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
 | 
				
			||||||
 | 
							    cfgno, inum, asnum, d->bEndpointAddress, maxp, j);
 | 
				
			||||||
 | 
							maxp = j;
 | 
				
			||||||
 | 
							endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Some buggy high speed devices have bulk endpoints using
 | 
						 * Some buggy high speed devices have bulk endpoints using
 | 
				
			||||||
	 * maxpacket sizes other than 512.  High speed HCDs may not
 | 
						 * maxpacket sizes other than 512.  High speed HCDs may not
 | 
				
			||||||
| 
						 | 
					@ -293,9 +356,6 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
 | 
						if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
 | 
				
			||||||
			&& usb_endpoint_xfer_bulk(d)) {
 | 
								&& usb_endpoint_xfer_bulk(d)) {
 | 
				
			||||||
		unsigned maxp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
 | 
					 | 
				
			||||||
		if (maxp != 512)
 | 
							if (maxp != 512)
 | 
				
			||||||
			dev_warn(ddev, "config %d interface %d altsetting %d "
 | 
								dev_warn(ddev, "config %d interface %d altsetting %d "
 | 
				
			||||||
				"bulk endpoint 0x%X has invalid maxpacket %d\n",
 | 
									"bulk endpoint 0x%X has invalid maxpacket %d\n",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue