Copy Fail Banner

CVE-2026-31431 (Copy Fail): Root with a Single Python Script — A 9-Year Linux Kernel Blight

On April 29, 2026, the security research team Theori disclosed a Linux kernel vulnerability codenamed Copy Fail, numbered CVE-2026-31431, with a CVSS score of 7.8 (High).

But what makes this vulnerability truly unsettling isn’t the score — it’s three facts:

  1. Extremely wide impact: Introduced in 2017, it has affected virtually every mainstream Linux distribution — Ubuntu, Debian, RHEL, Rocky, SUSE, Amazon Linux… none were spared
  2. Extremely low exploitation barrier: A 732-byte Python script, run by an unprivileged user to get a root shell — no race conditions, no multiple attempts
  3. Container escape capable: If you get an unprivileged user’s permissions inside a container, you can escape directly to the host

This is a chilling vulnerability.


Copy Fail in One Sentence

To understand this vulnerability, you don’t need to know kernel source code — just one simple mechanism:

The Linux kernel has something called a page cache. When you read a file, the kernel caches the file content in memory. Subsequent read/write operations work directly on the cached content without re-reading from disk.

Copy Fail exploits a code defect in the AF_ALG crypto subsystem. Through the splice() system call, it chains the page cache pages of a target file (such as /usr/bin/su) into the encryption operation’s data linked list. An out-of-bounds write during encryption directly modifies this page cache.

Key point: This modification only happens in memory — it does not trigger a disk write-back. So ordinary file integrity checking tools (like sha256sum) won’t detect the problem — the file on disk is intact, but the in-memory execution image has been tampered with.

The attacker changes one or two bytes of a setuid program like /usr/bin/su, and when it’s executed next, they get root directly.


Vulnerability Timeline

  • 2017: Commit 72548b093ee3 was merged into the mainline kernel. This was an optimization: the AF_ALG AEAD decryption path was changed to “in-place” operation, directly chaining user-supplied pages into the scatterlist to avoid an extra memory copy.
  • 2017–2026 (9 years): This optimization remained in the kernel, undiscovered as a vulnerability.
  • April 22, 2026: Greg Kroah-Hartman submitted the fix commit a664bf3d603d, titled “crypto: algif_aead – Revert to operating out-of-place” — reverting to out-of-place mode, acknowledging that the complexity of in-place optimization wasn’t worth it.
  • April 29, 2026: Theori publicly disclosed vulnerability details and PoC.
  • April 29–30, 2026: Major distributions urgently released security updates.

Affected Versions

The vulnerability was introduced with kernel commit 72548b093ee3 and fixed by a664bf3d603d.

The specific affected kernel version ranges:

Branch Affected Versions Safe Version
4.14–5.10 < 5.10.251 >= 5.10.251
5.15–6.1 < 6.1.170 >= 6.1.170
6.2–6.8 < 6.8.12 >= 6.8.12
6.9–6.10 < 6.10.11 >= 6.10.11
6.11–6.12 < 6.12.17 >= 6.12.17

Technical Deep Dive

If you’re interested in the details, here’s a simplified explanation:

The algif_aead module provides a user-space AEAD (Authenticated Encryption with Associated Data) interface through AF_ALG sockets. User programs send data to the kernel via sendmsg(), then use splice() or read() to get the encrypted/decrypted result.

The original design (< before 2017) used "out-of-place" operation: the input data was copied to a kernel buffer, encrypted/decrypted there, and then copied back to user space. Commit 72548b093ee3 (2017) attempted to optimize this by changing to “in-place” operation: instead of copying, it directly chained the user-provided pages into the crypto scatterlist. The assumption was that these pages were “read-only” and that the crypto operation would not modify the input data — but for AEAD decryption, the plaintext output is written to the same scatterlist position as the ciphertext input.

In the case of splice(), the pages come from the page cache of an arbitrary file. The decryption output overwrites the page cache contents — but only in memory, not on disk.

The PoC works like this:

1. Open a setuid binary (e.g., /usr/bin/su) as read-only
2. Use splice() to feed its page cache pages into an AF_ALG AEAD socket
3. Craft a ciphertext such that the decrypt output overwrites one or two key bytes in the page cache
4. The page cache now contains a modified version of /usr/bin/su
5. Execute the modified /usr/bin/su → the setuid execution grants root


Why It Took 9 Years to Discover

  • Not a typical memory corruption: It’s a semantic vulnerability rather than a classic buffer overflow
  • Requires combining multiple subsystems: The crypto subsystem + splice + page cache → the attack surface spans module boundaries
  • Different from usual exploitation paths: Most kernel exploits target driver bugs or use-after-free — this one targets a design assumption (in-place == safe)

What This Means for the Linux Ecosystem

Copy Fail isn’t the first nor will it be the last vulnerability of its kind. But it’s a particularly good example of an issue found through cross-subsystem security research — not just looking at one piece of code, but at how different parts of the kernel interact.

For system administrators, the lesson is clear: the “old kernel = stable kernel” mindset is dangerous. A vulnerability that existed for 9 years without being discovered doesn’t mean the kernel was secure — it means nobody had looked at that specific interaction.

For enterprise users still running kernels from 2018 or 2019, Copy Fail is the latest strong signal that kernel updates are not optional luxury items.


Our next article will provide a hands-on guide on how to check if your system is affected, how to fix it, and what to do if you can’t patch immediately. Stay tuned.

Last modified: 2026年7月6日

Author

Comments

Write a Reply or Comment

Your email address will not be published.