CVE-2026-46242: Exploração maliciosa do Epoll no Linux com privilégios de root

Os patches do php2shell (CVE-2026-109618 e CVE-2026-109619) para o PHP em fim de vida (EOL) já estão disponíveis. Como as respostas do atendimento de vendas estão mais demoradas do que o normal devido à alta demanda, a maneira mais rápida de obter os pacotes corrigidos é adquirir o ELS para Runtimes on-line (abre em uma nova aba). Leia as perguntas frequentes sobre os patches

Vá direto para um resumo gerado por IA desta postagem do blog

  • Resuma esta postagem com o Perplexity
  • Resuma esta postagem com o Gemini

A versão resumida

Ir para a versão completa ↓

O que: A vulnerabilidade “Bad Epoll”, registrada como CVE-2026-46242, é uma condição de corrida do tipo “use-after-free” no subsistema epoll do kernel do Linux. Na rota de limpeza da função ep_remove(), uma rota de fechamento limpa o link epoll do arquivo e continua a utilizá-lo, enquanto uma liberação simultânea do arquivo, ao detectar esse link limpo, libera o objeto subjacente a ele. Um usuário sem privilégios aproveita essa gravação indesejada para obter acesso ao diretório raiz.

Impacto: Um usuário local sem privilégios vence a corrida, transforma a gravação de 8 bytes em uma situação de “use-after-free” no controle de uma estrutura `file` por meio de um ataque “cross-cache” e, em seguida, escala para leitura arbitrária no kernel e sequestro do fluxo de controle – acesso root total. O PoC público (J-jaeyoung/bad-epoll, enviado ao Google kernelCTF) relata 99% de confiabilidade em um kernel 6.12, a mesma base do AlmaLinux 10.

Status: O bug é real e já foi corrigido no código-fonte original. Ele foi relatado de forma privada em fevereiro, corrigido em 24 de abril e divulgado publicamente em 30 de maio — a correção antecedeu a divulgação em cinco semanas, sem que tenha havido uso na prática. Inicialmente, tratava-se de um 0-day do kernelCTF, mas, para os defensores hoje, é um N-day com um exploit público.

Gravidade: o kernel.org e o NVD atribuem a ela uma pontuação CVSS de 7,8 (Alta: AV:L/AC:L/PR:L); a Red Hat atribui uma pontuação de 7,0, considerando a condição de corrida de aproximadamente 6 instruções como difícil de ser vencida. De qualquer forma, o resultado é o acesso como root, e a confiabilidade de aproximadamente 99% da demonstração de conceito (PoC) torna essa janela estreita um problema prático, e não teórico.

Por que isso é importante: Os sistemas vulneráveis são aqueles em que o isolamento local é o resultado: hospedagem compartilhada, servidores multilocatários, executores de CI e nós de contêineres que executam código não confiável. O epoll está na base de quase todos os serviços, portanto, não há nenhuma superfície de ataque que possa ser desativada. Uma LPE local é o evento que ultrapassa os limites neste caso.

Faça isso agora: não há uma solução de mitigação simples na configuração – o epoll não pode ser desativado. Isole a execução local não confiável e confirme se o kernel realmente contém a correção, em vez de confiar em uma tentativa fracassada de exploração. Um patch da KernelCare que não requer reinicialização está sendo analisado; ainda não há nada disponível nos repositórios. Detalhes a seguir.

Cansado de ter que agendar mais uma reinicialização de emergência?

O KernelCare aplica patches no kernel do Linux sem tempo de inatividade, interrupções ou janelas de manutenção de emergência.

Status do KernelCare (atualizado em 04/07/2026 — em análise): Essa é uma linhagem de kernel compartilhada: o RHEL, o AlmaLinux, o Rocky, o Oracle Linux e o CloudLinux, que pertencem à mesma versão principal, compartilham o mesmo ep_remove() código e exposição — considere “EL10” e “EL9” como um todo. A Red Hat classifica o RHEL 9 e o 10 como afetados (7/8 não afetados). O EL10 está afetado; é muito provável que o EL9 herde o commit de introdução retroportado. Ainda estamos verificando a reprodução e as compilações afetadas exatas. Nenhum patch do KernelCare concluiu a validação, e nenhum está disponível em nenhum feed ainda (rastreado como KCARE-27500). Não há nenhuma configuração que o cliente possa aplicar para mitigar o problema no momento — consulte a seção de mitigação.

Baixe o KernelCare

A versão completa

Há duas razões que podem levá-lo a encerrar este ticket antes do tempo, e ambas estão erradas.

O primeiro é o próprio arquivo README do PoC, que afirma que a falha afeta apenas kernels “baseados na versão 6.4 ou mais recentes” e considera seguros os kernels baseados na versão 6.1. Se você ler isso em uma máquina com CloudLinux 9 — baseada na versão 5.14 —, provavelmente concluirá que está fora do escopo. Mas você estaria errado. O segundo é uma execução limpa da exploração. Aponte o PoC público para um kernel em uma pequena VM, observe-o perder a corrida algumas centenas de milhares de vezes, e fica fácil escrever “não reproduzível, não afetado” e seguir em frente. Também está errado — e, no caso desse bug, isso é perigoso.

O Bad Epoll é uma condição de corrida do tipo “use-after-free” no subsistema eventpoll do kernel — a estrutura por trás das chamadas de sistema epoll das quais praticamente todos os serviços de rede na máquina dependem. A condição de corrida ocorre no caminho de limpeza da função ep_remove(), e a janela de oportunidade tem largura de aproximadamente seis instruções de CPU. Se você não aproveitar esse momento, nada acontece. Se você aproveitar essa janela — como faz a exploração pública com alta confiabilidade em um kernel 6.12 —, um usuário sem privilégios estará a caminho de obter privilégios de root.

Confirmou-se que a vulnerabilidade EL10 pode ser explorada e que a EL9 provavelmente foi afetada pelo commit de introdução retroportado; portanto, não se trata de uma interpretação cautelosa de um comunicado do fornecedor. Trata-se de um bug real, com uma correção real no código-fonte original e uma exploração pública já transformada em arma, que já consta de uma inscrição no kernelCTF.

Como funciona o Bad Epoll

O epoll mantém um struct eventpoll objeto, apoiado por um struct file, para cada instância do epoll. É importante desativá-la de forma correta, pois dois processos podem acabar fechando o mesmo recurso quase ao mesmo tempo: o processo de remoção do epoll e uma liberação simultânea do arquivo subjacente.

O bug é um pequeno erro de sequência nessa desativação. Dentro da função ep_remove(), o código antigo desativava a associação do arquivo ao epoll (file->f_ep) enquanto segura file->f_lock, e continuou usando esse mesmo arquivo e seus dados do eventpoll dentro da seção crítica. Uma operação simultânea __fput() Ao acionar o caminho rápido de liberação nesse intervalo, o valor NULL transitório é detectado f_ep, conclui que não há limpeza de epoll a ser feita e segue diretamente para f_op->release. Em uma configuração do tipo “epoll monitora epoll”, esse caminho libera o elemento monitorado struct eventpoll totalmente. O primeiro caminho ainda está em execução, e seu próximo hlist_del_rcu() grava por meio de um ponteiro incorporado na memória que acabou de ser liberada.

[Unprivileged local process]
│  creates linked epoll objects backed by struct file
▼
[Two close paths race inside ep_remove()]
│  path A clears file->f_ep, keeps using the file
│  path B (__fput) sees NULL f_ep, skips epoll cleanup
▼
[Path B frees the watched struct eventpoll / recycles the file slot]
│  path A's hlist_del_rcu() writes into freed memory
▼
[Attacker-controlled 8-byte use-after-free write]
▼
[Cross-cache reclaim gives control of a struct file]
▼
[Arbitrary kernel read + control-flow hijack]
▼
[uid=0 root shell]

A gravação em si ocorre oito bytes dentro da memória liberada, o que parece não ser grave até você acompanhar o que a exploração faz com ela. A cadeia pública utiliza quatro objetos epoll em dois pares: o fechamento de um par desencadeia a condição de corrida, enquanto o outro se torna a vítima. Isso transforma a gravação de 8 bytes em um “use-after-free” em um struct file, utiliza a recuperação de memória entre caches para substituir esse espaço por um objeto controlado pelo invasor e, em seguida, consegue realizar leituras arbitrárias no kernel e o sequestro do fluxo de controle.

O fato de a condição de corrida ser tão sutil é exatamente o motivo pelo qual é fácil avaliar mal a falha – e por que ela passou despercebida por anos. O mesmo commit de 2023 que a introduziu também introduziu uma condição de corrida semelhante, a CVE-2026-43074, que foi identificada e corrigida no início de 2026. Essa correção não resolveu a falha “Bad Epoll”. A aplicação de uma correção para o epoll neste ano não é prova de que ambas as falhas estejam presentes.

O que a correção do Upstream altera

A correção é pequena e independente, e é por isso que pode ser portada sem problemas. Ela impede que a função ep_remove() opere com uma referência desprotegida ao arquivo que está sendo removido.

O caminho corrigido coloca o arquivo na frente, usando uma referência que passa por epi_fget() e segurando um struct file *file __free(fput) proteger antes que toque file->f_lock. Enquanto essa referência for mantida, a contagem de referências do arquivo não pode cair para zero, portanto __fput() não consegue iniciar e o caminho de liberação simultânea não consegue liberar o arquivo ou seu objeto eventpoll da limpeza. Se não for possível liberar o pin, a função ep_remove() é interrompida antes de limpar f_ep, e o caminho de liberação segue o processo normal e mais lento de limpeza, que se sincroniza por meio do mutex eventpoll, em vez de ocorrer uma corrida de acesso.

Conceitualmente:

Before:  clear epoll link → keep using file → concurrent release frees it → write into freed memory
After:   pin file reference → do cleanup while pinned → concurrent release cannot free → release reference

Essa única alteração corrige as duas partes do bug: a liberação da variável monitorada struct eventpoll, e a reciclagem do struct file slot, enquanto o caminho original ainda acredita que detém um bloqueio válido.

Quem é afetado

A resposta curta para a família CloudLinux e AlmaLinux: as versões 9 e 10 estão afetadas e isso já foi confirmado; espera-se que a versão 8 não seja afetada.

Afetados:

  • CloudLinux 10 / AlmaLinux 10 (baseado na versão 6.12): Uma variante do PoC público, destinada exclusivamente a causar travamento, leva de forma confiável um host AlmaLinux 10 sem privilégios em ambiente bare metal ao pânico em questão de segundos — uma vulnerabilidade “use-after-free” explorável e transformada em arma, e não uma mera curiosidade de laboratório. Trata-se da mesma base 6.12 na qual a exploração completa obtém acesso root com 99% de confiabilidade no upstream.
  • CloudLinux 9 / AlmaLinux 9 (baseados no 5.14): Provavelmente afetados por meio do commit inicial que foi retroportado – a Red Hat lista o RHEL 9 como afetado porque o commit inicial foi retroportado para essa linha. A reprodução na linha 5.14 ainda está sendo verificada; portanto, considere-o como afetado até que haja confirmação, e não como algo comprovado internamente.

Não deve ser afetado; confirme antes de confiar nisso:

  • CloudLinux 8 / AlmaLinux 8 (baseado na versão 4.18): A Red Hat indica que o RHEL 7 e o 8 não foram afetados, e espera-se que o CL8 também não seja, por herança. Se um auditor ou cliente precisar de uma confirmação definitiva, verifique a fonte em vez de simplesmente afirmar isso.

A janela de versão é a primeira armadilha. O arquivo README do PoC descreve um intervalo da linha principal a partir da v6.4 e considera seguros os kernels baseados na v6.1. Isso é verdade para a linha principal, mas não se aplica ao Enterprise Linux, pois os fornecedores fazem o backport da alteração introdutória para versões muito mais antigas. Um kernel EL9 baseado na 5.14 está bem abaixo da v6.4 e ainda é afetado. Não faça suposições com base na versão do upstream para o seu sistema EL.

Uma reprodução malsucedida é a segunda armadilha. As explorações de corrida são extremamente sensíveis ao número de núcleos, ao agendamento, ao layout da pilha e à configuração de compilação. Um teste inicial em uma pequena VM com duas vCPUs não detectou nenhuma corrida e parecia estar tudo em ordem; um reprodutor mais robusto em um servidor físico multicore causou um pânico na mesma linha do kernel em questão de segundos. O problema estava no ambiente de teste inadequado, e não em um kernel corrigido. Não interprete a ausência de uma corrida detectada como garantia de segurança.

Portanto, verifique com base no código-fonte, e não na exploração. Usar o `grep` para procurar o hash do commit do código-fonte pode induzir a erro, pois os backports removem esse hash. Em vez disso, verifique se há o padrão de correção dentro da função `ep_remove()`:

grep -n 'epi_fget\|__free(fput)' /usr/src/kernels/$(uname -r)/fs/eventpoll.c

Se a função ep_remove() bloquear o arquivo com epi_fget() e um __free(fput) tenha cuidado antes de tocar file->f_lock, a correção está presente. Se elas estiverem ausentes, o kernel não está atualizado, e qualquer exploração maliciosa executada nele foi um falso negativo.

Aja agora para mitigar

Vamos ser diretos: não existe uma solução de mitigação de configuração que seja totalmente segura.

O epoll é uma interface essencial de chamadas de sistema. Nginx, PHP-FPM, mysqld, systemd — praticamente tudo em um servidor de produção depende dele, e ele está habilitado em todos os kernels de uso geral. Não há nenhum parâmetro sysctl para alterar, nenhum módulo para colocar na lista negra e nenhuma capacidade a ser removida que feche a rota vulnerável sem prejudicar as cargas de trabalho que geram receita para o servidor. Nem mesmo são necessários namespaces de usuário ou capacidades especiais; o pesquisador observa que ela pode ser acessada a partir de contextos restritos, incluindo a sandbox do renderizador de um navegador. Qualquer pessoa que ofereça uma solução de fortalecimento do epoll em uma única linha para isso está vendendo a você um produto defeituoso.

Como o bug é apenas local (AV:L, PR:L), as medidas de proteção duradouras são aquelas já conhecidas por todos:

  • Limite o número de usuários que podem executar código nos hosts afetados, pois esse bug requer um ponto de acesso local sem privilégios; quanto menos pontos de acesso, menor a exposição.
  • Isole a execução local não confiável e semiconfiável — código do cliente, tarefas de CI, etapas de compilação — dos hosts que você mais precisa proteger, ou transfira-a para kernels que você possa corrigir primeiro.
  • Priorize os hosts nos quais o isolamento local constitui a verdadeira barreira de segurança: hospedagem compartilhada, nós multilocatários, executores de CI e hosts de contêineres.
  • Confirme se o kernel contém a correção por meio da verificação do código-fonte descrita acima, em vez de inferir que está seguro com base em uma execução silenciosa da exploração.

Momento decisivo. Se um host não executar nenhum código local não confiável e tiver um grupo pequeno e confiável de usuários, o risco residual é menor e você pode aplicar patches em seu ritmo normal assim que uma errata ou um patch que não exija reinicialização for disponibilizado. Se um host executar código que você não controla — hospedagem compartilhada, CI, ambiente multilocatário —, trate-o como exposto a partir de hoje e coloque um patch que não exija reinicialização ou um kernel corrigido no início da fila assim que estiver disponível.

Aplicação de patches sem reinicialização

Esse é exatamente o tipo de falha para o qual existem correções sem reinicialização. A alteração do desenvolvedor original já está disponível, mas isso não protege um sistema em execução: o fornecedor precisa fazer o backport, você precisa instalar o pacote e a máquina precisa inicializar com o novo kernel. É nessa última etapa que o risco persiste, e é exatamente onde é mais difícil, justamente onde mais importa.

A correção consiste em uma pequena alteração de limpeza independente, o que a torna uma boa candidata a patch que não requer reinicialização. Trata-se de um backport direto do pino de referência ep_remove() do upstream, aplicado ao kernel em execução de modo que a limpeza em andamento não possa mais liberar o arquivo subjacente — a mesma garantia da correção do upstream, implementada sem a necessidade de reinicialização.

Para o CloudLinux e o AlmaLinux, a correção já foi identificada – trata-se de um backport direto do pino de referência ep_remove() do upstream (backport do RHEL 10, gerrit 257974). O backport do KernelCare ainda está em análise, com a reprodução no EL10 e no EL9 sendo verificada; portanto, nenhum patch concluiu a validação e nenhum está nos feeds de teste, principal ou ePortal ainda. O LibCare está fora do escopo aqui – trata-se de um bug exclusivo do kernel, portanto não há nenhum aspecto relacionado à biblioteca do espaço do usuário a ser corrigido.

Assim que uma versão estiver disponível, a implantação a partir do canal de testes (feed) é feita da seguinte maneira:

kcarectl --update --prefix test

Para confirmar se a versão do patch em execução foi criada na data de lançamento ou posteriormente:

kcarectl --info | grep kpatch-build-time

A data de compilação, por si só, não prova nada. Verifique diretamente o mapeamento do CVE, a errata do fornecedor, o padrão de origem ou o status do patch no KernelCare.

Baixe o KernelCare →

Detecção

Um epoll mal executado não deixa nenhuma assinatura clara no disco. A exploração ocorre inteiramente na memória do kernel — vencendo uma corrida de acesso, corrompendo um objeto liberado, reescrevendo o fluxo de controle —, de modo que as ferramentas de integridade de arquivos não têm nada para detectar. O gatilho é construído a partir de interfaces comuns (criação de instâncias epoll, registro de descritores, timerfds, fechamento deles) que são normais em qualquer host Linux. Isso leva a detecção ao âmbito comportamental, e cada um dos itens a seguir é uma pista, não uma prova:

  • Processos sem privilégios que criam e desativam um grande número de instâncias epoll e timerfds em loops curtos, o que corresponde a sobrecarregar uma situação de disputa acirrada.
  • Erros de kernel do tipo “oops” ou bugs de corrupção de lista no caminho de desativação do eventpoll, com assinaturas relacionadas ep_show_fdinfo, ep_clear_and_put, ep_eventpoll_release, ou __fput.
  • Falhas repetidas do kernel e reinicializações em um host multicore, sem que haja alterações de hardware ou configuração que justifiquem tais ocorrências – um gatilho que causa apenas falhas faz com que o sistema entre em pânico em segundos.
  • Um usuário local ou uma conta de serviço que obtém privilégios logo após uma sequência dos eventos acima, sem que haja um evento correspondente de sudo ou de login.

Se um código local não confiável ou parcialmente confiável for executado em um host EL9 ou EL10 exposto e você observar instabilidade no kernel concentrada no caminho de desativação do epoll, priorize a aplicação de patches e trate o host como algo que merece uma análise mais detalhada — novas contas ou chaves SSH, configuração de autenticação alterada, serviços inesperados — em vez de interpretar hashes de arquivos válidos como ausência de comprometimento.

Por que este é importante

O Bad Epoll não permite a execução remota de código. Ninguém consegue obter acesso root ao seu servidor pela internet com isso. Para os ambientes em que ele realmente atinge, isso é um consolo insignificante.

A hospedagem compartilhada executa o código dos clientes. Os executores de CI executam o que a última solicitação de pull lhes instruiu a fazer. Os contêineres e os nós do Kubernetes executam cargas de trabalho em diferentes níveis de confiança, e os hosts multilocatários existem especificamente para manter os locatários separados. Em cada um desses casos, uma escalada de privilégios local é o evento que todo o projeto se destina a impedir. Ela transforma código que tinha permissão para ser executado em código rodando como root, onde nunca deveria ter sido executado. O fato de o bug também ser acessível a partir de locais onde a maioria dos bugs do kernel não está, como a sandbox do renderizador de um navegador, apenas amplia a superfície de ataque.

A razão pela qual é fácil se enganar é a mesma pela qual isso é perigoso. Três sinais plausíveis apontam para “seguro” e todos induzem ao erro: a linha de versão “v6.4+” ignora os backports para o EL9 baseado na versão 5.14; uma execução malsucedida da exploração ignora o quão difícil é atingir uma condição de corrida de seis instruções sem esforço; e ter aplicado a correção do epoll relacionada no início deste ano não resolve nada neste caso. Confie em qualquer um deles e você classificará um host vulnerável como seguro.

O risco se concentra onde sempre se concentra: nos servidores que estão algumas atualizações atrasados, nos executores de CI de longa duração que ninguém reinicia, nos hosts multilocatários onde uma janela de manutenção é uma questão de negociação. Esses são precisamente os hosts em que uma vulnerabilidade do tipo “N-day”, com um PoC público, silenciosamente se transforma em um problema no mesmo dia — e aqueles em que um patch que não requer reinicialização faz a diferença entre corrigir o problema hoje e corrigi-lo no próximo trimestre.

Lista de verificação de medidas corretivas priorizadas

  • Considere o CloudLinux 9 e o CloudLinux 10 como afetados e confirmados. Não isente o CL9 com base na nota “v6.4+” – o commit inicial foi retroportado para a linha 5.14.
  • Confirme cada kernel com base na origem, e não no resultado da exploração: verifique a função ep_remove() para o epi_fget() + __free(fput) definir um padrão e considerar uma execução de PoC com falha como inconclusiva.
  • Não presuma que a afirmação “corrigimos um bug do epoll este ano” se aplique a este caso; a correção do CVE-2026-43074, que está relacionada, não resolve o problema do “Bad Epoll”.
  • Priorize os hosts nos quais o isolamento local constitui a barreira de segurança: hospedagem compartilhada, nós multilocatários, executores de CI, hosts de contêineres e de desenvolvimento que executam código não confiável.
  • Reduza e isole a execução local não confiável até que uma correção seja implementada. Não há nenhuma medida de mitigação por meio da configuração à qual se recorrer — o epoll não pode ser desativado.
  • Verifique o CloudLinux 8 diretamente na fonte antes de dizer a alguém que está tudo certo.
  • Procure por erros inesperados do kernel e atividades incomuns do epoll/timerfd no caminho de desativação do eventpoll, e considere os hashes de arquivos válidos como evidência insuficiente.
  • Aplique o patch do KernelCare que não requer reinicialização assim que for validado e incluído no feed, especialmente nos hosts mais difíceis de reiniciar. O patch ainda está em análise; as K-tags serão publicadas aqui assim que as versões forem lançadas.

Aplique patches em qualquer kernel, sem necessidade de reinicialização. Se você ainda não é usuário do KernelCare, este é um bom momento para descobrir como a aplicação de patches sem reinicialização protege sistemas Linux críticos, sem a necessidade de janelas de manutenção de emergência ou tempo de inatividade.

Adquira o KernelCare hoje mesmo →

Referências

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.

Índice
Obtenha as respostas sobre segurança de código aberto de que você precisa

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.