Recently, a significant security flaw was identified and fixed in the Linux Kernel's AMDGPU Direct Rendering Manager (DRM) subsystem. This vulnerability, now known as CVE-2024-27041, could potentially allow a local attacker to crash the system or trigger undefined behavior by causing a NULL pointer dereference. This post dives into what CVE-2024-27041 is, how it happens, and demonstrates how such a bug can be triggered.

What is CVE-2024-27041?

CVE-2024-27041 stems from the amdgpu_dm_fini() function, which is part of the AMDGPU display core driver found in the Linux kernel under drivers/gpu/drm/amd/amdgpu/amdgpu_dm.c.

The root cause: A missing NULL check on the adev->dm.dc structure, which stands for the display core data for an AMD GPU device. If the kernel tries accessing this structure when it's NULL, a null pointer dereference occurs, often leading to a kernel panic (system crash).

Component: Linux Kernel, DRM AMDGPU display driver

- Reporter: Found by Linux Verification Center (linuxtesting.org) using the static analyzer SVACE

The Problematic Code

Before the fix, parts of the amdgpu_dm_fini() function assumed that the adev->dm.dc structure was always present. However, under certain initialization/failure scenarios, it's possible for adev->dm.dc to be NULL before this function is called, which could result in an attempt to access a null pointer.

Before Patch

if (adev->dm.dc)
    dc_enable_dmub_notifications(adev->dm.dc);

if (adev->dm.dc)
    dc_deinit_callbacks(adev->dm.dc);

if (adev->dm.dc)
    dc_dmub_srv_destroy(adev->dm.dc);

What's wrong here?
Several checks for NULL are scattered, but it's possible that a new call between the checks could dereference a null pointer when adev->dm.dc is NULL. Plus, this design is messy and unclear.

Vulnerable Call

dc_enable_dmub_notifications(adev->dm.dc); // No guarantee adev->dm.dc is valid

If adev->dm.dc is NULL, this direct call will crash the kernel.

The Patch

The fix, merged into the mainline kernel, cleans up the checks. All operations that require a valid adev->dm.dc pointer are now within a single if block.

After Patch

if (adev->dm.dc) {
    dc_enable_dmub_notifications(adev->dm.dc);
    dc_deinit_callbacks(adev->dm.dc);
    dc_dmub_srv_destroy(adev->dm.dc);
}

Result:

You can see the official patch in the Linux Kernel mailing list commit, or view it on kernel.org.

Demonstrating the Exploit Scenario

This bug is tough to exploit deliberately because it depends on certain hardware or error cases during GPU initialization, but a simplified example illustrates the issue:

Suppose as a privileged user, you can trigger a GPU initialization failure or a rapid sequence of loading/unloading the AMDGPU driver (perhaps via PCI hotplug or by writing scripts that modulate GPU bindings). Under unlucky conditions, the kernel could end up calling amdgpu_dm_fini() while adev->dm.dc is NULL:

# Not a real exploit, but an idea of race conditions:
for i in $(seq 1 100); do
    modprobe amdgpu
    rmmod amdgpu
done

If the driver fails to allocate certain structures, adev->dm.dc can be NULL at teardown, and then—without the fix—the kernel will crash.

Takeaway for Admins and Users

Who is vulnerable: Anyone using a kernel affected by CVE-2024-27041, AMD GPUs, and the open-source AMDGPU driver.

What to do:
- Upgrade to a kernel version with the patch (Check your distribution's release notes in Ubuntu, Red Hat, Debian)
- If you compile your own kernel, ensure you include this fix or cherry-pick the commit from Linus’ tree.

Further References

- Linux Kernel Patch (lkml)
- Kernel.org Commit
- Linux Verification Center
- SVACE Static Analyzer
- CVE-2024-27041 on CVE databases

Conclusion

CVE-2024-27041 is a classic example of a kernel bug that could destabilize systems in the real world. Thanks to proactive static code analysis and speedy patching, the risk has been eliminated in supported kernels. Keep your system up-to-date and stay vigilant for such low-level bugs that can have widespread effects in production and desktop environments alike.

Timeline

Published on: 05/01/2024 13:15:49 UTC
Last modified on: 11/01/2024 16:35:14 UTC