A Race in AF_ALG: a 14-Year-Old Linux Kernel Hole Worth $113,337

Translated by a model; the original is in Russian.

· Security
A STAR Labs researcher found a race condition in the Linux kernel's crypto subsystem that lets an ordinary user become root and break out of a Docker container. The flaw, CVE-2025-39964, had lived in the code for roughly fourteen years.

cover.svg

Muhammad Alifa Ramdhan, a vulnerability researcher at STAR Labs, has published a retrospective on how he found and weaponized CVE-2025-39964 in the Linux kernel. Submitted to Google's kernelCTF program, it earned a reward of $113,337; his colleague Bing-Jhong Billy Jheng helped complete the exploit chain.

An attractive attack surface

The AF_ALG subsystem exposes the kernel's cryptographic API — encryption and decryption — to userspace. What drew the author's attention was that it can be reached from unprivileged code through the ordinary socket interface, with no special rights or configuration required. As far as he could tell, no earlier kernelCTF submission had used AF_ALG as its entry point.

It should not be confused with Copy Fail, disclosed in 2026 and honored at the Pwnie Awards: that bug also involves AF_ALG but is a straight logic flaw in the AEAD path. This one is a race between two threads sharing a single socket.

The flaw itself

When handling input, the kernel collects user data into a scatter-gather list and keeps state in an af_alg_ctx context. The merge flag means the last page still has room and the next chunk can be appended to it. The code implicitly assumed that if merge is true, the final block holds at least one entry.

The author tested that assumption with two threads. While a thread waits for send-buffer space, the socket lock is deliberately released. By carefully interleaving two sendmsg() calls and making one of them fail during the copy, the context can be driven into a state believed impossible: merge is true, yet the entry count is zero. The expression sgl->sg + sgl->cur - 1 then references sg[-1] — out of bounds.

From an out-of-bounds read to an arbitrary write

The overrun alone yields only a KASAN crash. The key insight came from Jheng: the memcpy_from_msg() path copies through copy_from_user, which validates only the userspace source address, not the destination. A bad destination returns EFAULT instead of crashing the kernel. That turns the bug into an oracle — guesses can be probed to locate the right address without rebooting on every miss.

With an arbitrary write in hand, the exploit overwrites core_pattern, the setting that names a core-dump handler. If its value begins with a |, the kernel runs the named program as root. By deliberately crashing a child process, the author gains root; and because AF_ALG is reachable from inside a container, the same path escapes Docker onto the host.

Age and fix

The vulnerable code traces back to a 2011 commit that shipped in Linux 2.6.38 — the bug lay dormant for about fourteen years. The real problem was not a single missing check but the assumption that only one thread builds the input. The patch makes that assumption a rule: while one sendmsg() runs, a second writer on the same socket receives -EBUSY.


Source: Lobsters

Comments

Sign in, to comment.

  • No comments yet.