rh_call_control() contains a buffer, tbuf, which it uses to hold USB descriptors. These discriptors are eventually copied into the transfer_buffer in the URB. The buffer in the URB is dynamically defined and is always large enough to hold the amount of data it requests. tbuf is currently statically allocated on the stack with a size of 15 bytes, regardless of the size specified in the URB. This patch dynamically allocates tbuf, and ensures that tbuf is at least as big as the buffer in the URB. If an hcd attempts to write a descriptor containing more than 15 bytes ( such as the Standard BOS Descriptor for hubs, defined in the USB3.0 Spec, section 10.13.1 ) the write would overflow the buffer and corrupt the stack. This patch addresses this behavior. Acked-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> Signed-off-by: Sean O. Stalley <sean.stalley@xxxxxxxxx> --- drivers/usb/core/hcd.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 014dc99..3e64e2d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -464,17 +464,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) struct usb_ctrlrequest *cmd; u16 typeReq, wValue, wIndex, wLength; u8 *ubuf = urb->transfer_buffer; - /* - * tbuf should be as big as the BOS descriptor and - * the USB hub descriptor. - */ - u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE] - __attribute__((aligned(4))); - const u8 *bufp = tbuf; unsigned len = 0; int status; u8 patch_wakeup = 0; u8 patch_protocol = 0; + u16 tbuf_size; + u8 *tbuf = NULL; + const u8 *bufp; might_sleep(); @@ -494,6 +490,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) if (wLength > urb->transfer_buffer_length) goto error; + /* + * tbuf should be at least as big as the + * USB hub descriptor. + */ + tbuf_size = max_t(u16, sizeof(struct usb_hub_descriptor), wLength); + tbuf = kzalloc(tbuf_size, GFP_KERNEL); + if (!tbuf) + return -ENOMEM; + + bufp = tbuf; + + urb->actual_length = 0; switch (typeReq) { @@ -691,6 +699,8 @@ error: bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT; } + kfree(tbuf); + /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); usb_hcd_unlink_urb_from_ep(hcd, urb); -- 1.8.1.2 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html