diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2021-05-26 11:32:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-05-27 13:46:21 +0200 |
commit | 7652dd2c5cb7b656471cc801d619fe24120643a3 (patch) | |
tree | 1df0b0a80088856a1f208a792c41558d7c4e611d /drivers/usb/core/urb.c | |
parent | 61a140f08ebb2e9f06b7889463f7ee9c162d98c2 (diff) | |
download | linux-7652dd2c5cb7b656471cc801d619fe24120643a3.tar.gz |
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>
Diffstat (limited to 'drivers/usb/core/urb.c')
-rw-r--r-- | drivers/usb/core/urb.c | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 279b3921ff8f..30727729a44c 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -410,6 +410,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) dev_WARN_ONCE(&dev->dev, (usb_pipeout(urb->pipe) != is_out), "BOGUS control dir, pipe %x doesn't match bRequestType %x\n", urb->pipe, setup->bRequestType); + if (le16_to_cpu(setup->wLength) != urb->transfer_buffer_length) { + dev_dbg(&dev->dev, "BOGUS control len %d doesn't match transfer length %d\n", + le16_to_cpu(setup->wLength), + urb->transfer_buffer_length); + return -EBADR; + } } else { is_out = usb_endpoint_dir_out(&ep->desc); } |