Recently, a security vulnerability—CVE-2024-26933—was patched in the Linux kernel’s USB core subsystem. This flaw, rooted in the sysfs attribute handling of USB ports, could have led to system hangs or deadlocks during specific device operations. This post offers an exclusive, easy-to-understand breakdown of what happened, how it was found and fixed, and what you need to watch out for.

Summary: What is CVE-2024-26933?

The vulnerability lies in how the Linux kernel manages USB port disablement via the sysfs attribute (/sys/class/.../disable). Under certain circumstances, such as parallel device removal or configuration change, the USB system could deadlock, halting both actions. This was traced to improper lock handling between sysfs attribute callbacks and USB core device removal.

Severity:
This bug could lead to system deadlocks, creating denial of service scenarios especially on systems that frequently hot-plug USB devices.

The Problem: Deadlock in Port "disable" Sysfs Attribute

In drivers/usb/core/port.c, two callback routines—disable_show() and disable_store()—allow userspace tools (or users) to view or change the "disable" status of a USB port via sysfs. Both acquire a lock on the parent hub device for thread/callback safety.

But, deadlock occurs when another process attempts to remove the device or change its configuration at the same time. Removal waits for all running sysfs attribute callbacks (like disable_show() or disable_store()), while those callbacks themselves wait for the lock—which cannot be released until the removal finishes.

Illustration

- Process 1: Runs echo 1 > /sys/.../disable, entering disable_store(), tries to grab hub lock.
- Process 2: Tries to remove the hub, must wait for all running sysfs callbacks, but already holds the hub lock.

How Was It Fixed? (With Code Snippet)

The solution is to use sysfs_break_active_protection(), a Linux kernel helper which tells sysfs not to wait for the attribute operation to finish before proceeding with device removal. To prevent the hub structure from being freed while in use, the code must acquire a reference to the hub object using hub_get() before breaking the protection and calling the attribute routines.

Patch Snippet

Below is an illustrative snippet based on the upstream patch (kernel.org commit):

static ssize_t disable_show(struct device *dev,
                           struct device_attribute *attr, char *buf)
{
    struct usb_port *port = to_usb_port(dev);
    struct usb_hub *hub;

    hub = hub_get(port->port_dev.parent);
    if (!hub)
        return -ENODEV;

    sysfs_break_active_protection();

    mutex_lock(&port->port_dev.parent->lock);
    // ... show code logic ...
    mutex_unlock(&port->port_dev.parent->lock);

    hub_put(hub);
    return ...;
}

static ssize_t disable_store(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count)
{
    struct usb_port *port = to_usb_port(dev);
    struct usb_hub *hub;

    hub = hub_get(port->port_dev.parent);
    if (!hub)
        return -ENODEV;

    sysfs_break_active_protection();

    mutex_lock(&port->port_dev.parent->lock);
    // ... store code logic ...
    mutex_unlock(&port->port_dev.parent->lock);

    hub_put(hub);
    return count;
}

Key Points

- sysfs_break_active_protection() is called before entering the potentially blocking code, so sysfs removal does not deadlock.

Exploit Details

- Attack Vector: Local process (root or privileged) writing to sysfs attributes, while another process removes or reconfigures the USB device/hub.
- Impact: Locked up kernel thread leading to unresponsive device or service, possible full system hang.
- Malicious Use: Could be abused by a local denial of service script that triggers mass port disables while simultaneously removing USB hubs.

A PoC (Proof of Concept) to trigger the bug could look like

# In one terminal (disable port)
echo 1 > /sys/class/usb_port/usbX/disable

# In another terminal at same time (remove hub/device)
echo '1-1' > /sys/bus/usb/drivers/usb/unbind

If the kernel doesn’t have the fix, these two actions in tight timing could deadlock the system.

Upstream kernel commit (mainline fix):

kernel.org commit a12344494cb3fdafbc7bd7a3aaea8cb3c776c505

Full patch diff:

lore.kernel.org linux-usb/20240306...

CVE Details:

CVE-2024-26933 - cve.org entry

Remediation and Advice

- Upgrade your kernel if you use systems that hot-plug USB devices, or if you run virtualized/hypervised environments reliant on sysfs for device management.
- Distributions: Check with your Linux vendor for security updates including this patch if you run Ubuntu, Debian, Fedora, SUSE, etc.
- Developers: Be extra careful with sysfs attribute callbacks and device locking! Even small logic oversights like this can freeze a production system.

Summary Table

| Key Aspect | Detail |
| --------------- | ------------------------------------------------- |
| CVE | CVE-2024-26933 |
| Component | Linux kernel USB core (drivers/usb/core/port.c) |
| Impact | Deadlock, Denial of Service |
| Attack Vector | Local, via sysfs operations and device removal |
| Patch Status| Landed in mainline, 2024-03-06 |
| Mitigation | Apply latest kernel update |

Final Notes

CVE-2024-26933 highlights how subtle kernel bugs, even not directly related to memory corruption or privilege escalation, can cause major reliability issues in Linux. This fix, simple as it looks, required real understanding of sysfs internals and device locking. Stay patched, and always review how your code interacts with kernel subsystems!

Feel free to share this post for awareness, and keep your kernels safe!


*This is an exclusive breakdown based on upstream sources and kernel patch analysis.*

Timeline

Published on: 05/01/2024 06:15:07 UTC
Last modified on: 07/19/2024 08:41:12 UTC