
Prova de conceito de exploit para CVE-2026-31431, uma escalada local de privilégios no kernel Linux por meio de escrita no cache de páginas do AF_ALG, alcançando root nas principais distribuições.
algif_aead ("Copy Fail")
Autor: Van Glenndon Enad
Descoberta Original: Theori / Xint Code Research Team (Taeyang Lee)
Publicado: 29 de abril de 2026
Severidade: Alta
Pontuação CVSS v3.1: 7.8
Vetor CVSS v3.1: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-787 (Gravação Fora dos Limites), CWE-269 (Gerenciamento Inadequado de Privilégios)
CVE-2026-31431, apelidada publicamente de "Copy Fail", é uma vulnerabilidade de escalada de privilégios local (LPE) de alta severidade no módulo algif_aead do kernel Linux — a interface de cifra AEAD da API criptográfica de espaço de usuário do kernel (AF_ALG). A falha origina-se de uma otimização de desempenho (operação in-place) introduzida em 2017 através do commit 72548b093ee3, que inadvertidamente permitiu que páginas de arquivo com suporte no page cache fossem colocadas no scatterlist de destino gravável durante uma operação criptográfica AEAD.
Ao encadear três subsistemas do kernel — sockets AF_ALG, a chamada de sistema splice() e o comportamento de gravação temporária (scratch) do algoritmo authencesn — um usuário local sem privilégios pode realizar uma gravação controlada de 4 bytes no page cache de qualquer arquivo legível. Tendo como alvo um binário setuid como /usr/bin/su, essa gravação corrompe a imagem executável em memória sem modificar o arquivo em disco, contornando assim ferramentas de integridade de arquivos em disco. A escalada de privilégios resultante para root é determinística — sem condição de corrida, sem offsets de kernel específicos por distribuição e sem privilégios especiais. Um exploit PoC público em Python de 732 bytes entrega shells de root no Ubuntu, Amazon Linux, RHEL e SUSE em uma única execução sem modificações.
| Componente | Detalhes |
|---|---|
| Subsistema Afetado | crypto/algif_aead.c — interface AEAD AF_ALG do kernel Linux |
| Vulnerabilidade Introduzida | Kernel Linux 4.14 (2017), commit 72548b093ee38a6d4f2a19e6ef1948ae05c181f7 |
| Versões Corrigidas | 6.18.22, 6.19.12, 7.0 |
| Commit da Correção | a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 |
| Distribuições Verificadas | Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL 10.1, SUSE 16 |
| Afetadas Implicitamente | Debian, Arch, Fedora, Rocky, AlmaLinux, Oracle Linux e qualquer distribuição executando um kernel sem correção compilado desde 2017 |
A vulnerabilidade esteve silenciosamente presente em todas as principais distribuições Linux por quase nove anos. De acordo com a Theori, o AF_ALG está habilitado na configuração padrão do kernel de praticamente todas as distribuições, o que significa que nenhum flag de compilação ou configuração especial é necessário para que um sistema seja vulnerável.
O kernel Linux expõe primitivas criptográficas ao espaço de usuário através da interface de socket AF_ALG (crypto/algif_aead.c). Em 2017, uma otimização de desempenho foi incorporada, permitindo que o algif_aead realizasse operações AEAD in-place — reutilizando o buffer de memória de origem como destino — para evitar cópias desnecessárias de dados.
A falha emerge quando o espaço de usuário alimenta a entrada no socket AF_ALG através da chamada de sistema splice(). Nesse caso, as páginas colocadas no scatterlist de origem são páginas do page cache — memória compartilhada gerenciada pelo kernel que dá suporte ao arquivo usado no splice. Devido à otimização in-place que define req->src = req->dst, essas páginas do page cache acabam no scatterlist de destino gravável. O algoritmo authencesn subsequentemente realiza uma gravação temporária em dst[assoclen + cryptlen], que resolve para um offset dentro dessas páginas do page cache — efetivamente gravando dados controlados pelo atacante na imagem em memória do arquivo usado no splice.
Como o page cache é compartilhado em todo o host, incluindo contêineres, uma gravação de um processo afeta as páginas em cache desse arquivo para todos os processos e contêineres no mesmo kernel.
A alteração problemática em algif_aead.c definiu req->src = req->dst e encadeou páginas de tag do scatterlist de origem no scatterlist de saída via sg_chain():
/* Otimização in-place de 2017 — commit 72548b093ee3 */
req->src = req->dst; /* origem == destino */
sg_chain(dst, n + 1, src_tag); /* páginas de tag encadeadas no dst gravável */
Quando splice() é usado para alimentar um arquivo no socket, as páginas do scatterlist têm suporte no page cache, não em memória anônima privada. Encadeá-las no scatterlist dst gravável viola a suposição de que o destino é memória privada gravável.
authencesnO template authencesn grava um valor temporário de número de sequência (seqno_lo, bytes 4–7 do AAD) em dst[assoclen + cryptlen]. Como dst agora contém páginas do page cache do arquivo usado no splice, essa gravação atinge um offset controlado pelo atacante dentro da imagem em memória do arquivo:
/* Gravação temporária do authencesn — offset determinado por assoclen + cryptlen */
scatterwalk_map_and_copy(seqno, dst,
req->assoclen + req->cryptlen,
sizeof(seqno), 1); /* grava no page cache */
Os 4 bytes gravados correspondem a seqno_lo, que o atacante controla através do payload AAD enviado via sendmsg().
Socket AF_ALG (SOCK_SEQPACKET)
│
│ splice() — entrega páginas com suporte em arquivo ao socket
▼
Otimização in-place do algif_aead
│ req->src = req->dst
│ páginas do page cache entram no scatterlist gravável
▼
Gravação temporária do authencesn
│ grava seqno_lo em dst[assoclen + cryptlen]
│ = 4 bytes escolhidos pelo atacante em offset de arquivo escolhido
▼
Corrupção do page cache (sem alteração em disco)
A correção (a664bf3d603d) reverte completamente a otimização in-place — o algif_aead agora sempre opera out-of-place, alocando um buffer de destino separado. Como origem e destino agora vêm de mapeamentos diferentes, as páginas do page cache em src nunca podem ser alcançadas pelo caminho de gravação de dst.