Commit 1eb1b69f authored by Sarah Sharp's avatar Sarah Sharp Committed by Greg Kroah-Hartman

USB: xhci: Check URB's actual transfer buffer size.

commit 99eb32db upstream.

Make sure that the amount of data the xHC says was transmitted is less
than or equal to the size of the requested transfer buffer.  Before, if
the host controller erroneously reported that the number of bytes
untransferred was bigger than the buffer in the URB, urb->actual_length
could be set to a very large size.

Make sure urb->actual_length <= urb->transfer_buffer_length.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 851834e4
...@@ -1092,7 +1092,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -1092,7 +1092,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td->urb->actual_length = td->urb->actual_length =
td->urb->transfer_buffer_length - td->urb->transfer_buffer_length -
TRB_LEN(event->transfer_len); TRB_LEN(event->transfer_len);
if (td->urb->actual_length < 0) { if (td->urb->transfer_buffer_length <
td->urb->actual_length) {
xhci_warn(xhci, "HC gave bad length " xhci_warn(xhci, "HC gave bad length "
"of %d bytes left\n", "of %d bytes left\n",
TRB_LEN(event->transfer_len)); TRB_LEN(event->transfer_len));
...@@ -1167,6 +1168,20 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -1167,6 +1168,20 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td_cleanup: td_cleanup:
/* Clean up the endpoint's TD list */ /* Clean up the endpoint's TD list */
urb = td->urb; urb = td->urb;
/* Do one last check of the actual transfer length.
* If the host controller said we transferred more data than
* the buffer length, urb->actual_length will be a very big
* number (since it's unsigned). Play it safe and say we didn't
* transfer anything.
*/
if (urb->actual_length > urb->transfer_buffer_length) {
xhci_warn(xhci, "URB transfer length is wrong, "
"xHC issue? req. len = %u, "
"act. len = %u\n",
urb->transfer_buffer_length,
urb->actual_length);
urb->actual_length = 0;
}
list_del(&td->td_list); list_del(&td->td_list);
/* Was this TD slated to be cancelled but completed anyway? */ /* Was this TD slated to be cancelled but completed anyway? */
if (!list_empty(&td->cancelled_td_list)) { if (!list_empty(&td->cancelled_td_list)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment