CVE-2024-26583 - Linux Kernel Async TLS Notify Use-After-Free Race Explained & Exploited

The Linux kernel, at the heart of just about every Linux system, occasionally faces subtle and critical bugs. One such issue, recently patched, is CVE-2024-26583. This vulnerability could lead to a race condition between asynchronous crypto notification and a socket close, opening doors to use-after-free (UAF) and possibly exploitation.

In this post, we’ll break down the bug, look at the fix, walk through a simple exploitation scenario, and help you check your systems!

🔍 The Vulnerability: Race Between Async Notify & Socket Close

TLS (Transport Layer Security) in the Linux kernel supports offloading some cryptographic processing to asynchronous crypto APIs. When a process uses recvmsg or sendmsg on a TLS-enabled socket, the kernel might issue crypto requests handled asynchronously—meaning in separate kernel threads.

Here's the crux:
- The process handling recvmsg/sendmsg might exit just after the async crypto handler signals completion.
- Any kernel code running just after completion notification could touch already-freed memory—a classical use-after-free bug.

In plain terms: if the kernel isn’t careful, a callback could trigger *after* something is freed, leading to memory corruption or escalation exploits.

🛑 The Original Code: Where Things Went Wrong

Consider this simplified (and somewhat pseudocode) look at how completion notification could race with close:

void tls_async_callback(void *data) {
    struct tls_context *ctx = (struct tls_context *)data;

    // Mark as complete (may wake up user sleeping on read/write)
    complete(&ctx->async_done);

    // ...but, as soon as we complete(), user thread may exit...
    // Any code accessing ctx here could UAF!
}

Kernel developers tried various locking and flag schemes, but these proved brittle. The real root: after complete(), the user thread could tear down the context, yet some kernel work might be pending.

💡 The Fix: Reference Counting to The Rescue

Instead of elaborate locking, developers used a classic pattern: reference counts. By holding an extra reference on the context for async operations, they ensure that the context isn’t freed until everything is truly finished.

Here's the gist of the fixed approach

// When starting an async TLS operation:
get_tls_ctx(ctx);  // take a ref

void tls_async_callback(void *data) {
    struct tls_context *ctx = (struct tls_context *)data;
    // Signal completion. After this, the user thread may exit,
    // so don't touch ctx unless you own a reference!
    complete(&ctx->async_done);

    // ...don't touch ctx members past here
    put_tls_ctx(ctx); // drop ref taken when operation started
}

Now, only the last reference frees the context, so all parties know when it's safe.

Patch reference:
- Upstream kernel patch

In theory, exploiting this bug requires

- Crafting a TLS socket (AF_INET/SOCK_STREAM with TLS),

Closing the socket or unmapping memory while async handlers are pending,

- Forcing the kernel to access freed memory, possibly overlapping with attacker-controlled allocations.

Sample userland “exploit-in-spirit” (unsafe, for learning only)

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <linux/tls.h>
#include <string.h>
#include <stdio.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, );

    // Setup sockaddr_in and connect/bind as needed...

    struct tls_crypto_info_crypto {
        // Minimal TLS 1.2 configuration...
    } crypto = { ... };

    setsockopt(sock, SOL_TLS, TLS_CRYPTO_INFO, &crypto, sizeof(crypto));

    // Kick off large sendmsg() that triggers async crypto
    char bigbuf[x100000];
    memset(bigbuf, 'A', sizeof(bigbuf));
    write(sock, bigbuf, sizeof(bigbuf));

    // Close immediately; kernel still processing asynchronously
    close(sock);

    // Kernel might still reference TLS context, which we just freed!
    return ;
}

Potential outcomes: kernel panic, memory corruption, or—if attacker controls reallocation—privilege escalation.

uname -r

# Compare your kernel version to the fixed commit
`
- Mitigation: Update to a kernel with the backported fix for CVE-2024-26583.

---

## 🛠 More Information

- Official CVE entry: NVD - CVE-2024-26583
- Linux kernel source:
Upstream kernel fix
- Linux distributions advisory:
- Red Hat Bugzilla
- Debian Security Tracker

---

## 🔚 Wrap-Up

CVE-2024-26583 is a great example of why kernel reference counting and careful completion handling is essential in async-heavy code. For server admins and kernel developers alike: track your kernel updates closely and patch rapidly, especially for subtle use-after-free races like this!

---

*Written exclusively for your reference. Reproduction requires attribution.*

Timeline

Published on: 02/21/2024 15:15:09 UTC
Last modified on: 03/15/2024 13:05:03 UTC