
Uma explicação estruturada da CVE-2026-31431 (Copy Fail), conectando as três alterações do kernel que introduziram a vulnerabilidade e permitiram sua exploração.
Uma falha lógica no template criptográfico authencesn, encadeada via AF_ALG e splice(), resultando em uma escrita controlada de 4 bytes no cache de páginas de qualquer arquivo legível do sistema. Sem condição de corrida, sem offsets, sem payload compilado. O mesmo script de 732 bytes obtém root em todas as distribuições Linux desde 2017.
CVE-2026-31431 - Copy Fail é uma falha lógica no template criptográfico authencesn do kernel Linux. Ela permite que um usuário local sem privilégios realize uma escrita controlada de 4 bytes no cache de páginas de qualquer arquivo legível do sistema, sem modificar o arquivo no disco.
O bug não existe em nenhum dos três componentes individualmente. Ele emerge da interação entre eles:``` 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'/>
## ***🧬 Análise de Causa Raiz***
<div id='primitive'/>
### ***A primitiva AF_ALG + splice()***
AF_ALG (*[AF_ALG = 38](https://docs.kernel.org/crypto/userspace-if.html#user-space-api-general-remarks)*) é um tipo de socket que expõe a API criptográfica do kernel para o espaço de usuário sem privilégios. Um processo sem privilégios pode:
1. Abrir um socket AF_ALG / SOCK_SEQPACKET.
2. Chamar bind() para qualquer template AEAD disponível exposto pela API criptográfica do kernel.
3. Definir uma chave criptográfica via setsockopt(SOL_ALG, ALG_SET_KEY, ...) no algoritmo configurado.
4. Chamar accept() para obter um socket de operação dedicado que lidará com solicitações de criptografia e descriptografia
5. Enviar dados elaborados usando sendmsg() e receber o resultado processado via recvmsg(), interagindo totalmente com o subsistema criptográfico do kernel.
Ele é habilitado por padrão na configuração do kernel de todas as principais distribuições (CONFIG_CRYPTO_USER_API_AEAD=y).
**[splice(2)](https://man7.org/linux/man-pages/man2/splice.2.html)** transfere dados entre descritores de arquivo sem copiar - ele passa referências a páginas, não cópias. O fluxo relevante:```
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)
The TX scatterlist do socket AF_ALG contém referências diretas às mesmas páginas físicas usadas pelo kernel para cada read(), mmap() e execve() do arquivo. Nenhuma cópia está envolvida.
Commit 72548b093ee3, algif_aead.c. Para descriptografia, a implementação:
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'/>
### ***A escrita fora dos limites em authencesn***
authencesn é o wrapper AEAD do kernel usado pelo IPsec com Números de Sequência Estendidos (RFC 4303). O IPsec usa números de sequência de 64 bits:
- seqno_hi - 32 bits superiores (bytes 0-3 do AAD)
- seqno_lo - 32 bits inferiores (bytes 4-7 do AAD)
Apenas seqno_lo é transmitido no fio; seqno_hi é contexto implícito. Para o cálculo de HMAC, o authencesn precisa reorganizar esses bytes: seqno_hi no início e seqno_lo no final da entrada do hash.