drivers/usb/host/xhci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
From: Seungjin Bae <eeodqql09@gmail.com>
The `xhci_urb_enqueue()` validates Bulk OUT transfers by checking if the
buffer length is a multiple of the packet size. However, it doesn't check
whether the endpoint's `wMaxPacketSize` is zero before using it as a
divisor in a modulo operation.
If a malicious USB device sends a descriptor with `wMaxPacketSize` set to
0, it triggers a divide-by-zero exception (kernel panic). This allows an
attacker with physical access to crash the system, leading to a Denial of
Service.
Fix this by adding a check to ensure `wMaxPacketSize` is greater than 0
before performing the modulo operation.
Fixes: 4758dcd19a7d ("usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers")
Signed-off-by: Seungjin Bae <eeodqql09@gmail.com>
---
drivers/usb/host/xhci.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0cb45b95e4f5..f22ee6cc3083 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1621,15 +1621,18 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
unsigned int *ep_state;
struct urb_priv *urb_priv;
int num_tds;
+ int maxp;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+ maxp = usb_endpoint_maxp(&urb->ep->desc);
if (usb_endpoint_xfer_isoc(&urb->ep->desc))
num_tds = urb->number_of_packets;
else if (usb_endpoint_is_bulk_out(&urb->ep->desc) &&
urb->transfer_buffer_length > 0 &&
urb->transfer_flags & URB_ZERO_PACKET &&
- !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc)))
+ maxp > 0 &&
+ !(urb->transfer_buffer_length % maxp))
num_tds = 2;
else
num_tds = 1;
--
2.43.0
On Sat, Jan 10, 2026 at 01:34:21PM -0500, pip-izony wrote: > From: Seungjin Bae <eeodqql09@gmail.com> > > The `xhci_urb_enqueue()` validates Bulk OUT transfers by checking if the > buffer length is a multiple of the packet size. However, it doesn't check > whether the endpoint's `wMaxPacketSize` is zero before using it as a > divisor in a modulo operation. > > If a malicious USB device sends a descriptor with `wMaxPacketSize` set to > 0, it triggers a divide-by-zero exception (kernel panic). This allows an > attacker with physical access to crash the system, leading to a Denial of > Service. How did you become aware of this problem? > Fix this by adding a check to ensure `wMaxPacketSize` is greater than 0 > before performing the modulo operation. Not necessary. This can never happen, because transfers to or from endpoints with wMaxPacketSize set to 0 are rejected in usb_submit_urb() with error code -EMSGSIZE. Alan Stern
On 1/11/26 00:08, Alan Stern wrote: > On Sat, Jan 10, 2026 at 01:34:21PM -0500, pip-izony wrote: >> From: Seungjin Bae <eeodqql09@gmail.com> >> >> The `xhci_urb_enqueue()` validates Bulk OUT transfers by checking if the >> buffer length is a multiple of the packet size. However, it doesn't check >> whether the endpoint's `wMaxPacketSize` is zero before using it as a >> divisor in a modulo operation. >> >> If a malicious USB device sends a descriptor with `wMaxPacketSize` set to >> 0, it triggers a divide-by-zero exception (kernel panic). This allows an >> attacker with physical access to crash the system, leading to a Denial of >> Service. > > How did you become aware of this problem? > >> Fix this by adding a check to ensure `wMaxPacketSize` is greater than 0 >> before performing the modulo operation. > > Not necessary. This can never happen, because transfers to or from > endpoints with wMaxPacketSize set to 0 are rejected in usb_submit_urb() > with error code -EMSGSIZE. > Only special embedded high-speed eUSB double isoch bandwidth devices can have isoch endpoints with wMaxPacketSize set to zero. This divide by zero case is only an issue for Bulk OUT endpoints, which as Alan said, will be rejected by usb_submit_urb() Thanks Mathias
On Sat, Jan 10, 2026 at 01:34:21PM -0500, pip-izony wrote: > From: Seungjin Bae <eeodqql09@gmail.com> > > The `xhci_urb_enqueue()` validates Bulk OUT transfers by checking if the > buffer length is a multiple of the packet size. However, it doesn't check > whether the endpoint's `wMaxPacketSize` is zero before using it as a > divisor in a modulo operation. > > If a malicious USB device sends a descriptor with `wMaxPacketSize` set to > 0, it triggers a divide-by-zero exception (kernel panic). This allows an > attacker with physical access to crash the system, leading to a Denial of > Service. Shouldn't such a device have been rejected before it got here? When can this happen, after a driver is bound to a device or before it? thanks, greg k-h
© 2016 - 2026 Red Hat, Inc.