The Linux kernel is a fundamental part of computers, servers, and millions of embedded systems everywhere. A lot of these devices use USB for everything from storage to communication. Recently, researchers identified and patched a bug in the Linux USB core code — tracked as CVE-2024-41035. This bug caused Linux to get endpoints mixed up for certain USB devices, which could lead to misconfiguration or improper device operation.

In this article, I’ll explain what happened, why it’s a real problem (even if you’re not a kernel developer), and how the fix works, with straightforward examples. No advanced USB or kernel knowledge needed.

What Really Happened? Short Story

A *syzbot* security fuzzer found that the Linux USB kernel code misunderstood some USB device descriptors. Specifically, some bits in the "endpoint address" (bEndpointAddress) that should have been ignored (reserved bits) were being wrongly used to tell endpoints apart. So, two endpoints looked “different” to Linux even when — by the USB rulebook — they really were the same.

This led to a possible scenario where, for one physical endpoint, Linux could create and assign two different logical endpoints with different types (say, one interrupt and one bulk endpoint, which is not allowed by the USB protocol).

That can cause instability and opens the door for potential attacks or misbehavior by malicious (or just buggy) USB devices.

Endpoint Descriptors 101

Every USB endpoint has an address. It’s stored in the bEndpointAddress field of its descriptor (a little chunk of 8 bytes describing how the hardware is set up).

The rest (bits 4-6): *Reserved* (must be zero, per USB spec)

The mistake? *Linux wasn’t ignoring bits 4-6.* If a device sent a descriptor with those bits not set to zero, Linux saw it as a different endpoint, even when everything else matched.

Why Is That Bad?

A normal, compliant USB device will never flip those reserved bits. But bugs happen. Or maybe a malicious gadget wants to confuse Linux into getting its endpoint list wrong. If the kernel thinks there are two endpoints (when really it’s just one with a sneaky descriptor), device handling gets wonky.

Exploit Scenario

Let’s say a device designer (or attacker) creates a USB device that reports two endpoint descriptors:

The other has reserved bits set to 1

Before the patch, Linux would treat them as *two* separate endpoints, with potential for chaos.

Here’s a snipped USB descriptor dump (just what matters)

/* Fake endpoint descriptor 1 (reserved bits zero) */
bEndpointAddress = x82; /* b10000010: IN, endpoint 2, reserved =  */

/* Fake endpoint descriptor 2 (reserved bits nonzero) */
bEndpointAddress = x92; /* b10010010: IN, endpoint 2, reserved = b001 */

Linux, up to this bug, thought "Oh, these are different! Two endpoints!"

The Fix (Patch)

The solution is clean and easy: Always clear (mask out) those reserved bits before comparing or using them.

In C code, that means

// Original code didn't clear reserved bits properly

unsigned int endpoint_addr = desc->bEndpointAddress;

// NEW (patched) code: clear reserved bits (4-6)
#define USB_ENDPOINT_NUMBER_MASK   xf
#define USB_ENDPOINT_DIR_MASK      x80
#define USB_ENDPOINT_ADDR_MASK     (USB_ENDPOINT_NUMBER_MASK | USB_ENDPOINT_DIR_MASK)

unsigned int endpoint_addr_clean = desc->bEndpointAddress & USB_ENDPOINT_ADDR_MASK;

This is done *immediately* when parsing the descriptors, so every check and operation after works with the correct, spec-compliant endpoint address.

Reference

- Original Linux kernel patch
- USB 2. specification, section 9.6.6 (Endpoint Descriptor)
- Syzbot bug report

Simulating the Exploit

If you want to see the broken behavior yourself (on an unpatched kernel), you could create a USB gadget with two endpoint descriptors like above, but with different reserved bits set.

// Pseudo gadget code (for Linux GadgetFS or similar)
struct usb_endpoint_descriptor endpoint_desc1 = {
    .bEndpointAddress = x82  // IN, endpoint 2, reserved bits 
};
struct usb_endpoint_descriptor endpoint_desc2 = {
    .bEndpointAddress = x92  // IN, endpoint 2, reserved bit 4 set!
};

Load this on your test board — if using a buggy kernel, you'll see two endpoints created in sysfs/procfs. Once the patch is applied, only one endpoint shows up, correctly.

Are You At Risk?

- This bug only affects you if you plug in a non-compliant/malicious USB device (with reserved bits set in endpoint addresses).

Standard, certified USB devices will *never* trigger this.

- But, in a world with emulated USB gadgets (think security dongles, car ECUs, virtual machines, etc.), it’s easy to imagine this being used for fuzzing or deeper kernel exploits.
- All Linux systems using an unpatched kernel with USB support are potentially affected if they interact with such devices.

Device misconfiguration or not working right

- A new attack surface on systems handling USB devices (think fuzzing, or chaining with other kernel bugs)

No known “remote root” attacks using this bug, but as the researchers say: *never trust input from devices*.

Conclusion

CVE-2024-41035 teaches a simple lesson: always mask out reserved bits when parsing hardware formats, even if you “assume” devices won’t set them. Thanks to the hard work of the kernel community (and tools like syzbot), this is now fixed.

If you're a user:

*Get your kernel up-to-date!*

If you're a developer:

*Always consult the hardware spec, and never trust “reserved, must be zero” to stay zero.*


References:
- Linux patch for CVE-2024-41035
- USB Endpoint Descriptor Spec
- Original syzbot Report


Stay safe, patch your systems, and remember: always zero your bits!

Timeline

Published on: 07/29/2024 15:15:12 UTC
Last modified on: 05/04/2025 12:57:27 UTC