Skip to content

Commit

Permalink
usb: rh_call_control tbuf overflow fix
Browse files Browse the repository at this point in the history
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@rowland.harvard.edu>
Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Sean O. Stalley authored and Greg Kroah-Hartman committed Aug 14, 2013
1 parent 726a85c commit e57e780
Showing 1 changed file with 17 additions and 7 deletions.
24 changes: 17 additions & 7 deletions drivers/usb/core/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -466,17 +466,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();

Expand All @@ -496,6 +492,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) {

Expand Down Expand Up @@ -693,6 +701,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
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);
Expand Down

0 comments on commit e57e780

Please sign in to comment.