[PATCH] usb: xhci: fix potential divide-by-zero in xhci_urb_enqueue()

pip-izony posted 1 patch 3 weeks, 6 days ago
drivers/usb/host/xhci.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
[PATCH] usb: xhci: fix potential divide-by-zero in xhci_urb_enqueue()
Posted by pip-izony 3 weeks, 6 days ago
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
Re: [PATCH] usb: xhci: fix potential divide-by-zero in xhci_urb_enqueue()
Posted by Alan Stern 3 weeks, 6 days ago
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
Re: [PATCH] usb: xhci: fix potential divide-by-zero in xhci_urb_enqueue()
Posted by Mathias Nyman 3 weeks, 5 days ago
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
Re: [PATCH] usb: xhci: fix potential divide-by-zero in xhci_urb_enqueue()
Posted by Greg Kroah-Hartman 3 weeks, 6 days ago
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