CVE-2024-36971 - Race Condition in Linux Kernel's __dst_negative_advice() Leads to Use-After-Free (UAF)

A critical race condition vulnerability—CVE-2024-36971—was discovered and patched in the Linux kernel, affecting the networking subsystem. This flaw lies in the improper handling of the socket destination cache (sk->dst_cache) inside the __dst_negative_advice() function, potentially leading to a *use-after-free* (UAF) scenario. The vulnerability was revealed after a relevant kernel commit and is especially triggered during usage with UDP sockets.

Below, you'll find a plain-English explanation of how this vulnerability occurs, details on the fix, original references, and a simplified proof-of-concept code illustrating the issue.

What’s the Vulnerability?

The Linux kernel uses caching in network sockets to optimize packet forwarding. Each socket (struct sock) can hold a pointer (sk->dst_cache) which is used to quickly find route entries. The kernel is meant to manage this pointer safely—including its release and reset—to avoid referencing freed (no-longer-valid) memory.

The problem in __dst_negative_advice() is that it releases (dst_release()) the cached route before clearing the reference (sk->dst_cache). Because the Linux kernel networking code is highly concurrent (and uses RCU—the Read-Copy-Update mechanism—to synchronize access), the wrong ordering can cause another parallel thread to access sk->dst_cache after the route memory has already been freed, leading to *use-after-free* bugs and potential exploitability.

*Then* clear sk->dst_cache

And *that* creates a race window, where another process or thread could touch the freed pointer.

Explaining the Impact

While this bug has existed for a long time, it only became apparent after recent changes in the networking stack (especially with how UDP sockets are handled). Attackers who can trigger route cache invalidation—such as sending network packets to and from UDP sockets in a controlled manner—may have a chance to trigger memory corruption or escalate privileges, depending on the kernel and system configuration.

Patch Commit (kernel.org)

- net: fix __dst_negative_advice() race

CVE Report

- CVE-2024-36971 at Mitre

OSS Security List

- oss-security Discussion

Reporter

- Clement Lecigne

Here’s a simplified idea of how the buggy code looked before the fix

// Faulty order: release before clearing
static void __dst_negative_advice(struct dst_entry *dst)
{
    struct sock *sk = dst->sk;
    if (sk) {
        dst_release(sk->sk_dst_cache); // BAD: releases memory
        sk->sk_dst_cache = NULL;       // BAD: clears pointer after release
    }
}

What should happen (Patched code):

// Correct order: clear then release
static void __dst_negative_advice(struct dst_entry *dst)
{
    struct sock *sk = dst->sk;
    if (sk) {
        struct dst_entry *old_dst = xchg(&sk->sk_dst_cache, NULL); // atomically clear
        dst_release(old_dst); // safe to release after pointer reset
    }
}

Exploit Details and Proof-of-Concept (Conceptual)

While no public real-world exploit has been shared (and writing a full exploit for a UAF in the network stack is non-trivial and dangerous), *conceptually* an attacker could:

Force route cache invalidation (e.g., by sending crafted packets, causing route updates).

3. Through race conditions, manage to have user-land observe inconsistent states or crash the kernel—potentially leading to privilege escalation or arbitrary code execution.

A minimal crash PoC concept

# Python pseudocode to repeatedly open/close UDP sockets to trigger race

import socket
import threading

def flood():
    for _ in range(1_000_000):
        s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
        s.connect(('::1', 12345))
        s.close()

threads = [threading.Thread(target=flood) for _ in range(8)]
for t in threads:
    t.start()
for t in threads:
    t.join()

*Note:* This won't work as a reliable exploit, but with enough stress and luck, it's possible to trigger unintended behavior in an unpatched kernel, especially in a debug/virtualized environment.

Patch and Remediation

- The bug is fixed in kernel commit ddb99ae5ab9.

Distributors are rapidly backporting the patch into stable kernels.

Mitigation: If you can’t immediately update, restrict access to untrusted users and untrusted network paths, especially for UDP (datagram) services.

Conclusion

CVE-2024-36971 is a prime example of a subtle, long-standing race condition bug in the Linux kernel’s core networking code, made visible by ongoing changes in how route cache is managed. Thanks to Clement Lecigne for tracking and identifying this issue. System administrators and Linux users should patch promptly to avoid exposure to local and network attacks exploiting this UAF vulnerability.


Stay safe—keep your systems updated, and always follow kernel and distribution advisories for critical security issues!


*This writeup is exclusive: simplified, summarized, and re-expressed for easy understanding.*

Timeline

Published on: 06/10/2024 09:15:09 UTC
Last modified on: 08/08/2024 14:49:52 UTC