
Eine strukturierte Erläuterung von CVE-2026-31431 (Copy Fail), die die drei Kernel-Änderungen miteinander verbindet, die die Schwachstelle eingeführt und ihre Ausnutzung ermöglicht haben.
Ein Logikfehler in authencesn, der über AF_ALG und splice() zu einem kontrollierten 4-Byte-Schreibzugriff in den Page Cache einer beliebigen lesbaren Datei auf dem System führt. Keine Race Condition, keine Offsets, kein kompilierter Payload. Dasselbe 732-Byte-Skript erlangt auf jeder Linux-Distribution seit 2017 Root-Rechte.
CVE-2026-31431 – Copy Fail ist ein Logikfehler in der kryptografischen Vorlage authencesn des Linux-Kernels. Er ermöglicht es einem unprivilegierten lokalen Benutzer, einen kontrollierten 4-Byte-Schreibzugriff in den Page Cache einer beliebigen lesbaren Datei auf dem System durchzuführen, ohne die Datei auf der Festplatte zu verändern.
Der Bug existiert in keiner der drei Komponenten für sich allein. Er entsteht durch ihr Zusammenspiel:``` 2011 ────────────────────────────────────────────────────────────────────── - authencesn added to the kernel (a5079d084f8b). - Uses the caller's destination scatterlist as scratch space. - Reorder ESN bytes before HMAC computation. - Only caller: internal xfrm layer. Harmless.
2015 ────────────────────────────────────────────────────────────────────── - algif_aead.c gains AEAD support with splice() path (104880a6b470). - splice() can deliver page cache pages to the TX scatterlist. - AF_ALG uses out-of-place operation: req->src != req->dst. - Page cache pages remain read-only. Not exploitable.
2017 ────────────────────────────────────────────────────────────────────── - In-place optimization in algif_aead.c (72548b093ee3). - Copies AAD+CT to RX buffer but chains authentication tag pages via sg_chain(). - Sets req->src = req->dst. - Page cache pages now reside in WRITABLE dst. - authencesn writes past boundary → page cache corruption.
2026 ────────────────────────────────────────────────────────────────────── - Copy Fail - CVE-2026-31431. Discovered by Theori / Xint Code. - Exploitable across all distros since 2017.
---
---
---
<div id='root-cause'/>
## ***🧬 Ursachenanalyse***
<div id='primitive'/>
### ***Das AF_ALG + splice()-Primitiv***
AF_ALG (*[AF_ALG = 38](https://docs.kernel.org/crypto/userspace-if.html#user-space-api-general-remarks)*) ist ein Socket-Typ, der die kryptografische Kernel-API für unprivilegierten Userspace verfügbar macht. Ein unprivilegierter Prozess kann:
1. Einen AF_ALG / SOCK_SEQPACKET-Socket öffnen.
2. per bind() an eine beliebige verfügbare AEAD-Vorlage binden, die von der Kernel-Krypto-API bereitgestellt wird.
3. Einen kryptografischen Schlüssel über setsockopt(SOL_ALG, ALG_SET_KEY, ...) auf dem konfigurierten Algorithmus setzen.
4. accept() aufrufen, um einen dedizierten Operations-Socket zu erhalten, der Ver- und Entschlüsselungsanforderungen verarbeitet
5. Präparierte Daten mit sendmsg() senden und das verarbeitete Ergebnis per recvmsg() empfangen, wobei vollständig mit dem Krypto-Subsystem des Kernels interagiert wird.
Es ist in der Kernel-Konfiguration aller großen Distributionen standardmäßig aktiviert (CONFIG_CRYPTO_USER_API_AEAD=y).
**[splice(2)](https://man7.org/linux/man-pages/man2/splice.2.html)** überträgt Daten zwischen Dateideskriptoren ohne Kopieren – es übergibt Referenzen auf Seiten, nicht Kopien. Der relevante Ablauf:```
open("/usr/bin/su") -> fd_file
pipe() -> pipe_rd, pipe_wr
# moves N bytes from the file into the pipe
# the pipe buffer now contains a reference to the same physical page in the page cache
splice(fd_file, pipe_wr, N)
# delivers that reference to the AF_ALG socket
# the TX scatterlist of algif_aead now points to the page cache page of /usr/bin/su
splice(pipe_rd, alg_fd, N)
Die TX-Scatterlist des AF_ALG-Sockets enthält direkte Referenzen auf dieselben physischen Seiten, die der Kernel für jeden read()-, mmap()- und execve()-Aufruf der Datei verwendet. Es ist keine Kopie beteiligt.
Commit 72548b093ee3, algif_aead.c. Für die Entschlüsselung:
In-place operation: RX SGL (req->dst): [ user buffer: AAD (copy) || CT (copy) ] --sg_chain--> [ Tag (page cache pages) ] req->src = req->dst = RX SGL
Result: page cache pages from /usr/bin/su are now part of the WRITABLE scatterlist passed to the crypto algorithm.
<div id='authencesn'/>
### ***Der Schreibzugriff außerhalb der Grenzen in authencesn***
authencesn ist der Kernel-AEAD-Wrapper, der von IPsec mit erweiterten Sequenznummern (RFC 4303) verwendet wird. IPsec verwendet 64-Bit-Sequenznummern:
- seqno_hi - die oberen 32 Bits (Bytes 0-3 der AAD)
- seqno_lo - die unteren 32 Bits (Bytes 4-7 der AAD)