CVE-2026-31431 'Copy Fail': A Privilege Rebellion That Only Edits the 'Photocopy'
The Hidden Crack in the Library: When the Cache Becomes a Battlefield
Imagine a grand old library. Deep in the stacks, precious originals are locked behind iron gates, touchable only by the librarian—root. Ordinary readers like us can only borrow photocopies, neatly arranged in the reading room, fine to browse but forbidden to alter. This is daily life in the Linux filesystem: real files on disk are the originals, while the page cache is the reading-room copy. For speed, the system caches frequently read file contents in memory; programs usually read this 'shadow' rather than the disk itself.
This time, an uninvited guest—CVE-2026-31431, codename Copy Fail—slipped into the reading room. It never pried open the vault, yet it left faint ink marks on the photocopies. An unprivileged user, with no write permission, successfully tampered with the in-memory file image and, via arbitrary code execution, quietly ascended to the root throne. The attack rewrites not the original, but the supposedly inviolable 'photocopy'.
> What is the page cache? > The page cache is a memory caching mechanism in the Linux kernel to boost I/O performance. When a file is read, the kernel loads its contents into physical memory page by page (typically 4KB). Subsequent accesses come straight from memory, avoiding slow disk operations. This greatly accelerates the system—but also creates a subtle separation between the 'memory version' and the 'disk version' of a file. The attacker exploits exactly this separation, polluting the memory image without ever touching disk.
Setuid's Phantom of Trust: How Ordinary Users Briefly Become Superuser
In the Linux permission world, setuid is like an ancient magic badge. Programs marked with the setuid bit, when run by ordinary users, cause the process to temporarily inherit the file owner's permissions (usually root). The classic example is passwd: changing your password requires writing to /etc/shadow, writable only by root. So the system makes passwd root-owned with setuid enabled, trusting it won't turn evil.
That trust, well-intentioned, became Copy Fail's opening. The attacker need not modify the setuid binary on disk—only pollute its image in the page cache. When the program executes, the kernel still treats it as the 'trusted original', though it is in fact a ghostly altered version. Like a guard holding an apparently intact key, unaware the teeth have been quietly filed—the door still opens, but the guard has become an inside man.
Splice's Zero-Copy Magic: Handing Over the Original, Not a Photocopy
Why does the system mistake a 'read-only photocopy' for a writable draft? The answer lies in splice(), a high-performance kernel mechanism.
The traditional read() path is a chain of handoffs: disk → page cache → copy into a user-space buffer, paying a copy cost each time. splice() pursues maximum efficiency—it does not copy data; it attaches the struct page from the page cache directly onto a pipe_buffer. The pipe holds a reference to the memory page, not a copy. The pipe can then be passed seamlessly to other kernel consumers, such as network or crypto interfaces.
> A zero-copy analogy > It's as if the librarian stops photocopying books for each reader and instead pushes the precious original (page cache) onto the reading desk—readers just look, no extra copying. Blazing fast, but the 'original' is now exposed to many more code paths. If later stages don't strictly enforce 'read-only', the consequences are dire.
AF_ALG and AEAD: The User Interface to Kernel Cryptography
The Linux kernel has a built-in crypto framework. To save user space from reimplementing algorithms, it exposes the AF_ALG socket family: user programs submit data to the kernel for hashing, encryption, decryption, or authentication, just like using a socket. Copy Fail targets AEAD—Authenticated Encryption with Associated Data—which splits data into an encrypted body and associated data (AD) that stays plaintext but is authenticated.
Algif_aead's In-Place Optimization: The Fatal 'Shared Memory' Assumption
A 2017 kernel change introduced in-place operation in algif_aead: input and output buffers may share the same memory, saving a copy. This assumption—that the provided buffer is writable—holds for normal user-space buffers. But when the buffer comes from a splice()'d pipe_buffer, it points to read-only page cache pages. The kernel failed to distinguish the two, and tragedy unfolded: read-only cache pages treated as writable scratch space.
Authencesn's Four-Byte Ghost: The Real Culprit of the Unauthorized Write
The write itself is triggered by the AEAD template authencesn (authenc + Extended Sequence Number, used in IPsec ESP etc.). While constructing the authentication input, it writes a 4-byte sequence number field at roughly AD length + ciphertext length. Normally this write lands in a writable output buffer or temporary area—but in in-place mode, input equals output, so the write lands directly on the page cache page referenced by the pipe_buffer.
More insidiously, this write occurs before authentication tag verification. Even if decryption ultimately fails and the kernel returns EBADMSG, the page cache pollution is already done. The attacker needs no valid ciphertext—a failed request alone rewrites 4 bytes.
> Why are 4 bytes lethal? > In a binary, 4 bytes can rewrite a jump instruction, a conditional check, or a key data structure. By repeatedly issuing requests with precisely controlled offsets, the attacker performs 'minimally invasive surgery' on a setuid program's memory image, planting a backdoor with no disk trace.
The Full Attack Chain: From Reading to Tampering to the Throne
1. The attacker picks a readable-but-not-writable target—typically a setuid-root program.
2. Via splice(), its contents are fed into a pipe; the pipe_buffer holds references to page cache pages.
3. The pipe data is submitted to AF_ALG's AEAD interface.
4. algif_aead processes it in-place, assuming the buffer is writable.
5. authencesn writes the 4-byte sequence number at the computed position, directly polluting the page cache.
6. Repeat the operation to make multiple precise modifications to the memory image.
7. Execute the setuid program; the system loads the tampered page cache version, and the attacker gains root.
The whole process is *Living off the Land*: no disk changes, no permission changes, no file-monitoring triggers—just a 'ghostly tampering' completed entirely in memory. That is what makes it both elegant and dangerous.

Defense: Repairing the Crack in Trust
The most direct and effective protection is updating the kernel: remove the in-place logic in algif_aead, forcing input/output separation so writes can never land on page cache pages. If upgrading immediately is not possible, disable the AF_ALG-related modules and restrict access to that interface. The fundamental fix remains applying official patches promptly, leaving this memory ghost nowhere to hide.
In this contest between memory and privilege, Copy Fail reminds us: performance optimizations are a double-edged sword, and trust models demand constant scrutiny. Linux's strength comes from its openness and efficiency—and its security depends on every developer and user.
---
References 1. Linux kernel documentation: Page Cache overview. 2. Linux man pages: the setuid permission model. 3. Kernel source analysis: splice() zero-copy implementation. 4. AF_ALG and AEAD framework technical documentation. 5. CVE-2026-31431 official patch notes and analysis reports.