·6 min read·Blog

Copy Fail: A Quick Fix and Analysis

Siddharth Singh

Sr. Security Researcher

Image

Introduction

Copy Fail is a local privilege escalation (LPE) vulnerability in the Linux kernel that has been present in every mainstream distribution shipped since 2017. Discovered by Xint Code and publicly disclosed on April 29, 2026, the bug allows any unprivileged local user to gain root access using a 732-byte Python script.

It affects Ubuntu, Debian, RHEL, SUSE, Amazon Linux, Arch, Fedora, and WSL2; anything running an unpatched kernel from the last nine years.

How it Works

The root cause is a 2017 "optimization" in algif_aead.c, part of the kernel's AF_ALG crypto API. That commit made AEAD optimization operate "in-place" by setting req->src = req->dst; both the source and destination of the crypto operation pointed to the same scatterlist.

This becomes exploitable when splice() is involved. When data is passed through this function, the kernel doesn't copy it, instead it passes references to page cache pages, the kernel's cached copy of on-disk files. Because of the in-place design, those page caches ended up chained into the "writable" destination scatterlist.

An attacker can exploit this to write 4 bytes at a time into the page cache of any readable file including the setuid binaries like /usr/bin/su. The write modifies only the in-memory cached copy, not the on-disk file, so the file integrity tool checks will return an okay and won't detect the change. The page cache is also shared across container boundaries, making this a container escape primitive.

To read further in detail, you can visit the original write-up here.

The Fix

The upstream patch a664bf3d603d reverts the in-place optimization entirely. Source and destination are separated:

  • req->src now points to the TX Scatterlist (where splice chains page cache pages)
  • req->dst now points to the RX Scatterlist (the user's recvmsg buffer)

Page caches are never placed in the writable destination, eliminating the write primitive. As the commit message reads: "There is no benefit in operating in-place in algif_aead since the source and destination come from different mappings."

Mitigation for General Linux Users

Linux has shipped patched kernels, update and reboot.

After rebooting, verify that the vulnerability is mitigated by attempting to bind a socket with the faulty module; if patched, this should either succeed harmlessly (the bug is fixed in the crypto code itself) or fail if the module has been blacklisted by kmod.

python3 -c 'import socket; s=socket.socket(38,5); s.bind(("aead","gcm(aes)"))'

Option 2: Disable the Module (If not in use)

If you can't reboot or update immediately, disable the algif_aead module:

echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/disable-algif.conf
sudo rmmod algif_aead

This prevents the module from loading (or unloads it if already loaded). For the vast majority of systems, this breaks nothing — dm-crypt, LUKS, kTLS, IPsec, SSH, and OpenSSL/GnuTLS in their default configurations don't use AF_ALG. Only applications explicitly configured to use the AF_ALG userspace interface (like OpenSSL with the afalg engine enabled) would be affected.

Mitigation for WSL2 Users (Important)

WSL2 runs its own Linux kernel managed by Microsoft. As of writing this, May 2026, Microsoft has not yet shipped a patch for the WSL2 kernel, so users are required to take action themselves. There are 3 options below, from simplest to most thorough:

Option 1: Blacklist the Module via .wslconfig

Add the following to C:\Users\<YOUR_USERNAME>\.wslconfig:

[wsl2]
kernelCommandLine=module_blacklist=algif_aead

Then restart WSL:

wsl --shutdown
wsl

This works because the default WSL2 kernel compiles algif_aead as a loadable module (CONFIG_CRYPTO_USER_API_AEAD=m), not built-in. The kernel boot parameter prevents it from ever loading.

Option 2: Recompile the WSL2 Kernel with the Module Disabled

For a more permanent solution, compile a custom kernel with the vulnerable module removed entirely.

Install build dependencies inside your WSL2 Ubuntu:

sudo apt update
sudo apt install -y build-essential flex bison libssl-dev libelf-dev \
    bc dwarves cpio kmod rsync git

Clone, configure, and build:

git clone --depth=1 -b linux-msft-wsl-6.6.y \
    https://github.com/microsoft/WSL2-Linux-Kernel.git
cd WSL2-Linux-Kernel
cp Microsoft/config-wsl .config
scripts/config --disable CRYPTO_USER_API_AEAD
make olddefconfig
make -j$(nproc)
sudo make modules_install

Copy the built kernel to Windows and point .wslconfig at it:

# From WSL, copy the kernel out
cp arch/x86/boot/bzImage /mnt/c/Users/<YOUR_USERNAME>/bzImage

Edit C:\Users\<YOUR_USERNAME>\.wslconfig:

[wsl2]
kernel=C:\\Users\\<YOUR_USERNAME>\\bzImage

Restart WSL:

wsl --shutdown
wsl

Verify with uname -r; expect a trailing + on the version string.

Option 3: Cherry-picking the Upstream Fix

Instead of disabling the module, you can apply the actual kernel patch to the WSL2 kernel source, preserving the AF_ALG functionality.

cd WSL2-Linux-Kernel
git remote add upstream https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
git fetch upstream a664bf3d603d --depth=1
git cherry-pick a664bf3d603d

There may be a merge conflict, but the patch is small and straightforward to backport. Then build and install as in Option 2.

Verifying the Fix

Run this quick check to confirm the exploit path is closed:

python3 -c 'import socket; s=socket.socket(38,5); s.bind(("aead","gcm(aes)"))'

If mitigated, you should see:

OSError: [Errno 97] Address family not supported by protocol

Analysis: How did this happen?

Copy Fail can best be classified as an Insecure Coding Practice — an unsafe optimization broke a memory isolation invariant. It is not an inherent design flaw or weakness in the AF_ALG API.

The AF_ALG interface is a reasonable design for exposing kernel crypto to userspace. The original pre-2017 code used separate source and destination buffers and was safe. The vulnerability was introduced by an implementation shortcut within a sound design.

Root Cause

The 2017 commit 72548b093ee3, authored by Stephan Mueller and reviewed by crypto maintainer Herbert Xu, introduced in-place AEAD operations to algif_aead.c. The commit message focuses entirely on crypto correctness; how AAD is copied, how tag pages are chained, how in-place cipher operations are achieved for both encryption and decryption. It includes test vectors demonstrating correct output. From a crypto standpoint, it is thorough and well-documented work.

What is entirely absent from the commit message, the code comments, and the review is any consideration of where the pages in these scatterlists might originate. The words "splice" and "page cache" do not appear. The critical assumption — that TX SGL pages are private buffers that can safely be linked into a writable destination — is never stated, because within the crypto subsystem, it seemed self-evident.

"Over"-Compartmentalization

The Linux kernel is roughly 30 million lines of code, divided into subsystems which are each maintained by specialists. The division of labour is expected and quite necessary, however, this is partially what causes such issues which emerge primarily due to what we have termed as "over" compartmentalization. In this case the issue emerged due to the cross-functionality between the crypto author, VFS author and authencesn algorithm author's works being integrated in a way that led to a vulnerability.

This is a recurring issue with certain large scale projects where ideas while implemented well, can lead to problems if the entire project is divided between too many people who would otherwise not overlook vulnerabilities and testing within their own domain. Hence, without overloading each developer, a proposed solution for companies is to assign certain authors whose job is to oversee commits and changes entirely from a cross-section POV, where the logic doesn't just need to solve the stated problem, but attention is also paid to the unintended consequences of such a change.

References

We use cookies to provide essential site functionality and, with your consent, to analyze site usage and enhance your experience. View our Privacy Policy