aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-08-27 17:36:24 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:18 -0400
commit99eb32db45061443ab7552b8fdceae68b90fde55 (patch)
treee42df1118729ba46166876ea5685d6216b540c2f /drivers
parent9191eee7b8a0e18c07c06d6da502706805cab6d2 (diff)
USB: xhci: Check URB's actual transfer buffer size.
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: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/xhci-ring.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 4142c04b5adf..b4fab00105d4 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1092,7 +1092,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
1092 td->urb->actual_length = 1092 td->urb->actual_length =
1093 td->urb->transfer_buffer_length - 1093 td->urb->transfer_buffer_length -
1094 TRB_LEN(event->transfer_len); 1094 TRB_LEN(event->transfer_len);
1095 if (td->urb->actual_length < 0) { 1095 if (td->urb->transfer_buffer_length <
1096 td->urb->actual_length) {
1096 xhci_warn(xhci, "HC gave bad length " 1097 xhci_warn(xhci, "HC gave bad length "
1097 "of %d bytes left\n", 1098 "of %d bytes left\n",
1098 TRB_LEN(event->transfer_len)); 1099 TRB_LEN(event->transfer_len));
@@ -1167,6 +1168,20 @@ static int handle_tx_event(struct xhci_hcd *xhci,
1167td_cleanup: 1168td_cleanup:
1168 /* Clean up the endpoint's TD list */ 1169 /* Clean up the endpoint's TD list */
1169 urb = td->urb; 1170 urb = td->urb;
1171 /* Do one last check of the actual transfer length.
1172 * If the host controller said we transferred more data than
1173 * the buffer length, urb->actual_length will be a very big
1174 * number (since it's unsigned). Play it safe and say we didn't
1175 * transfer anything.
1176 */
1177 if (urb->actual_length > urb->transfer_buffer_length) {
1178 xhci_warn(xhci, "URB transfer length is wrong, "
1179 "xHC issue? req. len = %u, "
1180 "act. len = %u\n",
1181 urb->transfer_buffer_length,
1182 urb->actual_length);
1183 urb->actual_length = 0;
1184 }
1170 list_del(&td->td_list); 1185 list_del(&td->td_list);
1171 /* Was this TD slated to be cancelled but completed anyway? */ 1186 /* Was this TD slated to be cancelled but completed anyway? */
1172 if (!list_empty(&td->cancelled_td_list)) { 1187 if (!list_empty(&td->cancelled_td_list)) {