CVE-2024-42226 - Understanding and Exploiting the Linux Kernel xHCI handle_tx_event() Vulnerability
A new Linux kernel vulnerability, CVE-2024-42226, affects the USB xHCI (Extensible Host Controller Interface) subsystem. The bug lies in how the kernel's xHCI driver handles Transfer Events that don't reference a valid Transfer Request Block (TRB). This post explains what went wrong, shows the vulnerable code, how it was fixed, and discusses how an attacker could weaponize this issue. Simple language is used to help anyone understand and learn from this unique vulnerability.
What is CVE-2024-42226?
In certain cases, the Linux xHCI USB stack tried to handle USB Transfer Events that didn’t actually point to a valid request or TRB. The vulnerable function, handle_tx_event(), would continue executing "business as usual," risking a crash or unpredictable behavior since later code might try to access a non-existent endpoint ring.
The root problem: The code did not bail out early enough when given weird or malformed Transfer Events.
This logic error could be triggered by a malicious device presenting specially-crafted USB events. While it’s not a classic privilege escalation or code execution hole on its own, a system crash (DoS) is possible.
Where is the bug?
The troublesome code is in the xHCI host controller driver—found in drivers/usb/host/xhci-ring.c inside the Linux kernel source. This driver is responsible for handling all USB 3.x (and some 2.x) traffic on platforms using the xHCI standard.
Here is the original commit fixing this bug.
Here’s a simplified version showing the original (buggy) logic
static void handle_tx_event(struct xhci_hcd *xhci, struct xhci_event_ring *er,
struct xhci_generic_trb *event)
{
struct xhci_ep_ctx *ep_ctx;
struct xhci_ring *ep_ring = /* get endpoint ring for this event */;
struct xhci_virt_ep *ep;
// Some events won't have a TRB nor a ring!
if (!ep_ring) {
if (completion_code == COMP_SUCCESS)
goto cleanup; // <-- Only skips if success; others continue
// ... vulnerable code continues...
}
if (ep->skip && ep_ring)
// This might dereference ep_ring even when it's NULL
handle_skip(ep);
// ... rest of handler ...
}
What's wrong?
When a Transfer Event doesn’t reference a valid TRB (and thus does not have an endpoint ring), the function might still try to use fields belonging to ep_ring (like ep->skip). This is unsafe and could panic the kernel or corrupt memory.
### The Patch/Fix
The kernel fix ensures the function returns early for such edge cases, before trying to use pointers that could be NULL. Here’s the critical portion of the patch (cleaned up for clarity):
if (!ep_ring) {
// No TRB for this completion event, just clean up and return
return;
}
// It's now always safe to access ep_ring below
if (ep->skip && ep_ring)
handle_skip(ep);
// ... continue normal processing ...
Now, if there’s no endpoint ring associated, the function gracefully returns without trying to handle anything further.
Who can exploit this?
An attacker with control of a USB device attached to the victim computer can trigger and abuse this vulnerability.
Exploit Scenario
1. Custom USB peripheral: The attacker builds a program for a microcontroller (such as a cheap Arduino-like board) that acts as a USB device.
2. Malformed Events: The device starts a transfer, then issues a Transfer Event that is invalid (doesn't actually point to any real TRB and has no endpoint ring).
3. Crash or Hang: The vulnerable Linux kernel's xHCI driver receives this bogus event and mishandles it, potentially dereferencing invalid pointers and leading to a kernel panic (DoS), freezing, or system instability.
Here is a (pseudocode) snippet illustrating how a malicious device might behave
// Pseudocode for microcontroller
send_usb_transfer();
// Now send transfer event with an invalid pointer
send_transfer_event_with_no_trb();
// Host running vulnerable kernel might crash when handling this event
Real World
While this is mostly a Denial of Service attack (DoS), it can be combined with other kernel issues for more serious impact. It’s a valuable lesson in defensive programming when handling hardware events in the kernel.
References
- Upstream Fix / Commit:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=687fa04c29faee7953042edb8ffb2106fab3dceb
CVE Record:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-42226
Linux Kernel Source (xhci-ring.c, mainline):
https://elixir.bootlin.com/linux/latest/source/drivers/usb/host/xhci-ring.c
How to Fix and Protect Yourself
- Apply kernel updates: If you run Linux on servers, desktops, or embedded devices with USB, update to a kernel version containing the patch (v6.10 or backported security patch).
Conclusion
*CVE-2024-42226* is a great example of how subtle input validation bugs can cause system-wide instability in low-level code—especially when hardware and software interact. While not the flashiest vulnerability, it underlines how USB device security is just as important as ever. Stay patched and don’t let rogue USB gadgets plug into sensitive computers!
Timeline
Published on: 07/30/2024 08:15:07 UTC
Last modified on: 07/30/2024 20:12:08 UTC