Skip to contentSkip to conversation

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

PATCH In review Alan Stern 3 participants 3 messages May 26, 2021 – May 27, 2021

Subsystems (2)
lore
Share & tools
lore

Alan Stern

author
#0 lore raw

PATCH 1/1 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.

---

[as1961]

 Documentation/driver-api/usb/error-codes.rst |    3 +++
 drivers/usb/core/urb.c                       |    6 ++++++
 2 files changed, 9 insertions(+)
drivers/usb/core/urb.c +6 -0
Index: usb-devel/drivers/usb/core/urb.c
===================================================================
@@ -410,6 +410,12 @@ int usb_submit_urb(struct urb *urb, gfp_
 		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);
 	}
Documentation/driver-api/usb/error-codes.rst +3 -0
Index: usb-devel/Documentation/driver-api/usb/error-codes.rst
===================================================================
@@ -61,6 +61,9 @@ USB-specific:
 			(c) requested data transfer length is invalid: negative
 			    or too large for the host controller.
 
+``-EBADR``		The wLength value in a control URB's setup packet does
+			not match the URB's transfer_buffer_length.
+
 ``-ENOSPC``		This request would overcommit the usb bandwidth reserved
 			for periodic transfers (interrupt, isochronous).
 
Reviewed-by on v1 1/1
#1 lore raw
Quoted 6 lines · Alan Stern

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.

Quoted 7 lines

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.

Looks good.

Quoted 41 lines

---

[as1961]

 Documentation/driver-api/usb/error-codes.rst |    3 +++
 drivers/usb/core/urb.c                       |    6 ++++++
 2 files changed, 9 insertions(+)

Index: usb-devel/drivers/usb/core/urb.c
===================================================================

drivers/usb/core/urb.c +6 -0
@@ -410,6 +410,12 @@ int usb_submit_urb(struct urb *urb, gfp_
 		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);
 	}

Index: usb-devel/Documentation/driver-api/usb/error-codes.rst
===================================================================

Documentation/driver-api/usb/error-codes.rst +3 -0
@@ -61,6 +61,9 @@ USB-specific:
 			(c) requested data transfer length is invalid: negative
 			    or too large for the host controller.
 
+``-EBADR``		The wLength value in a control URB's setup packet does
+			not match the URB's transfer_buffer_length.
+
 ``-ENOSPC``		This request would overcommit the usb bandwidth reserved
 			for periodic transfers (interrupt, isochronous).
 
#2 lore raw
In reply to Alan Stern
Quoted 29 lines · Alan Stern

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.

---

[as1961]

 Documentation/driver-api/usb/error-codes.rst |    3 +++
 drivers/usb/core/urb.c                       |    6 ++++++
 2 files changed, 9 insertions(+)

Index: usb-devel/drivers/usb/core/urb.c
===================================================================

drivers/usb/core/urb.c int usb_submit_urb(struct urb *urb, gfp_ · line 418

Quoted 9 lines
drivers/usb/core/urb.c +6 -0
@@ -410,6 +410,12 @@ int usb_submit_urb(struct urb *urb, gfp_
 		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;
+		}

Looks good, let's see if this catches anything :)

now queued up, thanks.

greg k-h