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

USB: core: Check buffer length matches wLength for control transfers

A type of inconsistency that can show up in control URBs is when the
setup packet's wLength value does not match the URB's
transfer_buffer_length field. The two should always be equal;
differences could lead to information leaks or undefined behavior for
OUT transfers or overruns for IN transfers.

This patch adds a test for such mismatches during URB submission. If
the test fails, the submission is rejected with a -EBADR error code
(which is not used elsewhere in the USB core), and a debugging message
is logged for people interested in tracking down these errors.

Reviewed-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/20210526153244.GA1400430@rowland.harvard.edu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
7652dd2c 61a140f0

+9
+3
Documentation/driver-api/usb/error-codes.rst
··· 61 61 (c) requested data transfer length is invalid: negative 62 62 or too large for the host controller. 63 63 64 + ``-EBADR`` The wLength value in a control URB's setup packet does 65 + not match the URB's transfer_buffer_length. 66 + 64 67 ``-ENOSPC`` This request would overcommit the usb bandwidth reserved 65 68 for periodic transfers (interrupt, isochronous). 66 69
+6
drivers/usb/core/urb.c
··· 410 410 dev_WARN_ONCE(&dev->dev, (usb_pipeout(urb->pipe) != is_out), 411 411 "BOGUS control dir, pipe %x doesn't match bRequestType %x\n", 412 412 urb->pipe, setup->bRequestType); 413 + if (le16_to_cpu(setup->wLength) != urb->transfer_buffer_length) { 414 + dev_dbg(&dev->dev, "BOGUS control len %d doesn't match transfer length %d\n", 415 + le16_to_cpu(setup->wLength), 416 + urb->transfer_buffer_length); 417 + return -EBADR; 418 + } 413 419 } else { 414 420 is_out = usb_endpoint_dir_out(&ep->desc); 415 421 }