Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: Gadget: dummy-hcd: Fix shift-out-of-bounds bug

The dummy-hcd driver was written under the assumption that all the
parameters in URBs sent to its root hub would be valid. With URBs
sent from userspace via usbfs, that assumption can be violated.

In particular, the driver doesn't fully check the port-feature values
stored in the wValue entry of Clear-Port-Feature and Set-Port-Feature
requests. Values that are too large can cause the driver to perform
an invalid left shift of more than 32 bits. Ironically, two of those
left shifts are unnecessary, because they implement Set-Port-Feature
requests that hubs are not required to support, according to section
11.24.2.13 of the USB-2.0 spec.

This patch adds the appropriate checks for the port feature selector
values and removes the unnecessary feature settings. It also rejects
requests to set the TEST feature or to set or clear the INDICATOR and
C_OVERCURRENT features, as none of these are relevant to dummy-hcd's
root-hub emulation.

CC: <stable@vger.kernel.org>
Reported-and-tested-by: syzbot+5925509f78293baa7331@syzkaller.appspotmail.com
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/20201230162044.GA727759@rowland.harvard.edu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
c318840f 9389044f

+23 -12
+23 -12
drivers/usb/gadget/udc/dummy_hcd.c
··· 2118 2118 dum_hcd->port_status &= ~USB_PORT_STAT_POWER; 2119 2119 set_link_state(dum_hcd); 2120 2120 break; 2121 - default: 2121 + case USB_PORT_FEAT_ENABLE: 2122 + case USB_PORT_FEAT_C_ENABLE: 2123 + case USB_PORT_FEAT_C_SUSPEND: 2124 + /* Not allowed for USB-3 */ 2125 + if (hcd->speed == HCD_USB3) 2126 + goto error; 2127 + fallthrough; 2128 + case USB_PORT_FEAT_C_CONNECTION: 2129 + case USB_PORT_FEAT_C_RESET: 2122 2130 dum_hcd->port_status &= ~(1 << wValue); 2123 2131 set_link_state(dum_hcd); 2132 + break; 2133 + default: 2134 + /* Disallow INDICATOR and C_OVER_CURRENT */ 2135 + goto error; 2124 2136 } 2125 2137 break; 2126 2138 case GetHubDescriptor: ··· 2293 2281 */ 2294 2282 dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50); 2295 2283 fallthrough; 2284 + case USB_PORT_FEAT_C_CONNECTION: 2285 + case USB_PORT_FEAT_C_RESET: 2286 + case USB_PORT_FEAT_C_ENABLE: 2287 + case USB_PORT_FEAT_C_SUSPEND: 2288 + /* Not allowed for USB-3, and ignored for USB-2 */ 2289 + if (hcd->speed == HCD_USB3) 2290 + goto error; 2291 + break; 2296 2292 default: 2297 - if (hcd->speed == HCD_USB3) { 2298 - if ((dum_hcd->port_status & 2299 - USB_SS_PORT_STAT_POWER) != 0) { 2300 - dum_hcd->port_status |= (1 << wValue); 2301 - } 2302 - } else 2303 - if ((dum_hcd->port_status & 2304 - USB_PORT_STAT_POWER) != 0) { 2305 - dum_hcd->port_status |= (1 << wValue); 2306 - } 2307 - set_link_state(dum_hcd); 2293 + /* Disallow TEST, INDICATOR, and C_OVER_CURRENT */ 2294 + goto error; 2308 2295 } 2309 2296 break; 2310 2297 case GetPortErrorCount: