Skip to content

CONCEPT Cited by 1 source

Copy Fail — CVE-2026-31431

Copy Fail (CVE-2026-31431) is a Linux kernel local-privilege-escalation vulnerability disclosed publicly by Xint Code on 2026-04-29. The bug is a 4-byte out-of-bounds write in the kernel crypto API's authencesn wrapper (the AEAD wrapper for algorithms like authencesn(hmac(sha256), cbc(aes))), triggered from unprivileged user-space via the AF_ALG socket family + the algif_aead module. By using splice() to chain a target file's page-cache pages into the crypto operation's scatterlist, an attacker can taint the cached pages of a setuid-root binary (canonically /usr/bin/su, present on essentially every Linux distribution) and get 4-byte chunks of shellcode executed with root privileges on the next execve().

The upstream fix (commit a664bf3d603d) reverts a 2017 in-place-crypto optimisation in algif_aead that chained destination and reference pages together in a scatterlist without enforcing write-boundary constraints. The canonical Xint write-up is at xint.io/blog/copy-fail-linux-distributions.

Exploit mechanics (summary)

  1. Cache reference. Open /usr/bin/su as O_RDONLY and read() to populate the page cache. Use splice() on the file descriptor to pass the page-cache references into an AF_ALG crypto scatterlist.
  2. Setup. Create an AF_ALG socket, bind() to authencesn(hmac(sha256),cbc(aes)), set a key, accept a request socket — all unprivileged.
  3. Write construction. For each 4-byte shellcode chunk, construct the crypto request so the authencesn wrapper's internal 4-byte write lands at the chosen offset in /usr/bin/su's cached pages.
  4. Trigger. recvmsg() initiates decryption; the authencesn wrapper writes its scratch bytes past the legitimate output region into the target scatterlist page. The operation returns -EBADMSG, but the 4-byte write has already landed in the global page cache.
  5. Execution. execve("/usr/bin/su") loads the tainted page cache. Because su is setuid-root, the injected shellcode runs with root privileges.

The exact vulnerable code path (from the Linux source):

scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);

Why this bug is structurally interesting

  • Unprivileged reachable. AF_ALG sockets + algif_aead are accessible to any user; no capabilities required.
  • Page cache is shared. Modifying a cached page of a setuid binary effectively edits that program for all users until the page is evicted — no need to write to the on-disk binary (hashes stay clean against package manifests; on-disk integrity checks don't detect the exploit).
  • 4 bytes is enough. Chunk-by-chunk writes assemble full shellcode over multiple crypto operations.
  • Setuid-root targets are universal. /usr/bin/su ships on essentially every distribution.
  • 2017 regression. The bug was introduced by an in-place-crypto optimisation that predates the disclosure by ~nine years — canonical example of a performance optimisation creating a latent security hazard.

Mitigation surface

Three levers, in increasing order of desirability:

  1. Unconditional algif_aead module removalecho "install algif_aead /bin/false" > /etc/modprobe.d/... then rmmod algif_aead. The researchers' recommended workaround. Coarse: breaks any software legitimately using the kernel crypto API via AF_ALG. Cloudflare attempted this in staging on 2026-04-29 evening; dependency conflicts surfaced and the attempt was rolled back (patterns/staging-caught-mitigation-failure).
  2. Targeted bpf-lsm hook denial — eBPF program on socket_bind hook that denies AF_ALG binds for everyone except an explicit allow-list of legitimate callers. Surgical where module removal is coarse. Canonical Cloudflare mitigation (systems/cloudflare-bpf-lsm + patterns/bpf-lsm-allowlist-hook-denial).
  3. Patched kernel via scheduled reboot — upstream commit a664bf3d603d backported to LTS 6.12 and rolled through ERR once the backport lands. Long-cycle — Cloudflare's biweekly cadence didn't close the gap before disclosure.

Detection

Running any variant of the exploit produces a distinctive trace in kernel logs (not publicly disclosed in detail by Cloudflare, but referenced as "the exploit leaves a distinctive trace in kernel logs when it runs" — the basis for the 48-hour retroactive threat-hunt). Independent of signature detection, behavioral detection on the process-execution chain (script interpreter → kernel crypto subsystem → setuid-root binary) flagged the exploit pattern within minutes during Cloudflare's internal validation — with "no signature update, no rule change, no human intervention".

A one-liner mitigation-verification test from the researchers:

python3 -c 'import socket; s = socket.socket(socket.AF_ALG,
  socket.SOCK_SEQPACKET, 0);
  s.bind(("aead","authencesn(hmac(sha256),cbc(aes))"));'

On a mitigated machine: PermissionError: [Errno 1] Operation not permitted (or FileNotFoundError, depending on mitigation type). On an unmitigated vulnerable machine: successful bind.

Seen in

Last updated · 451 distilled / 1,324 read