CVE-2021-46919 - Fixing a DMA Engine Security Flaw in the Linux Kernel

The Linux kernel is the backbone of many systems, running on servers, desktops, embedded devices, and more. Discovering vulnerabilities in such critical infrastructure can have severe impacts. In this post, we'll cover CVE-2021-46919, a security issue in the Linux kernel's DMA Engine (specifically the Intel Data Streaming Accelerator - IDXD), discuss the flaw, show some example code, walk through the exploit conditions, and link to authoritative references.

What is CVE-2021-46919?

CVE-2021-46919 is a vulnerability in the dmaengine subsystem of the Linux kernel. The flaw concerns a permission mishandling when changing the work queue (WQ) size in the Intel IDXD driver. In simple terms, this bug allowed users to modify the WQ size when they shouldn't have been able to, potentially resulting in undefined behavior or security risk.

Component: Linux kernel's dmaengine (specifically, the idxd driver)

- Problem: The code mistakenly allows users to resize a DMA work queue when the device is enabled but the WQ is disabled.
- Risk: Changing driver configurations when the device is running can cause unexpected results, data corruption, or security issues.

How Did the Vulnerability Happen?

The Linux kernel's idxd driver manages DMA work queues. You should only be able to change the work queue (WQ) size when the device itself is disabled, to ensure safety.

However, in the problematic code, the check only confirmed the WQ's state, not the whole device's state. This oversight let an attacker modify kernel object sizes while the device was enabled, possibly leading to privilege escalation or system instability.

Fixed in:
- Kernel commit cf8c171f81

The Code: Vulnerable and Patched

Here's a simplified illustration of the logic flaw and its fix.

Vulnerable code snippet

static ssize_t wq_size_store(struct device *dev, ... , const char *buf, size_t count)
{
    // ...parsing and setup...

    if (wq->state == IDXD_WQ_DISABLED) { // <-- only checks WQ state!
        wq->size = new_size;        // could happen while device is enabled
        // ...
    }
    // ...
}

Fixed code snippet

static ssize_t wq_size_store(struct device *dev, ... , const char *buf, size_t count)
{
    // ...parsing and setup...

    if (device->state == IDXD_DEVICE_DISABLED) { // <-- now checks device state
        wq->size = new_size;
        // ...
    }
    // ...
}

Key Fix: The condition was updated to require that the device (not just the WQ) be disabled before allowing a size change.

How Could This Be Exploited?

Since WQ size is stored in kernel memory, letting an unauthorized or unprivileged user write to this attribute while device operations are ongoing allows for unpredictable effects or might be leveraged to:

Escalate privileges under certain conditions

An attacker with local system access could use the sysfs interface (/sys/class/dma/idxd*) and issue a write to the WQ size attribute while the device is enabled, bypassing intended safety checks.

Sample exploit (pseudo)

# Assume WQ is disabled, device is enabled (for vulnerable kernel)
echo 128 > /sys/class/dma/idxd/wq/size
# This should not have worked but does in the vulnerable version

On patched systems: The write will fail unless the device is disabled.

Kernel versions before June 2021 containing the Intel IDXD driver and DMAengine subsystem

- Systems using Intel Data Streaming Accelerator with user access to relevant /sys interfaces

Official References

- Linux Kernel Commit Fix (cf8c171f81)
- NVD CVE Report
- LKML Patch Discussion

Conclusion

CVE-2021-46919 shows how even small permission mistakes in kernel code can be serious. If you run Linux systems with the relevant DMA hardware, update your kernel. It's another reminder that kernel developers need to be super careful about when and how device properties can be changed.

Timeline

Published on: 02/27/2024 07:15:08 UTC
Last modified on: 04/10/2024 14:46:43 UTC