
Ferramenta de detecção e mitigação de vulnerabilidades para os bugs Copy Fail e Dirty Frag (CVE-2026-31431, CVE-2026-43284, CVE-2026-43500)
# vcheck Auditar um host Linux remoto via SSH para as vulnerabilidades de módulo de kernel Copy Fail e Dirty Frag e, opcionalmente, aplicar mitigações: | CVE | Name | Módulos afetados | | -------------- | ------------------ | --------------------------------------------------- | | CVE-2026-31431 | Copy Fail | `algif_aead` | | CVE-2026-43284 | Dirty Frag (IPsec) | `esp4`, `esp6`, `ipcomp4`, `ipcomp6`, `xfrm_user` | | CVE-2026-43500 | Dirty Frag (RxRPC) | `rxrpc`, `kafs` | Para cada módulo afetado, o vcheck relata se ele está atualmente carregado, embutido no kernel em execução, possui rastros passados nos logs do kernel, possui sockets `AF_ALG` ativos (apenas Copy Fail) e se já está na lista negra em `/etc/modprobe.d/`. Com `-fix`, o vcheck relata o estado inicial, escreve um trecho `cve-XXXX-XXXXX-disable.conf` para qualquer módulo que ainda não esteja na lista negra, então reexecuta as verificações e relata o estado final. Com `-fix -unload`, o vcheck também tenta descarregar módulos afetados que estavam carregados antes da correção, então usa a verificação final para confirmar se ainda estão carregados. Com `-fix -rebuild-initramfs`, o vcheck reconstrói o initramfs para o kernel atualmente em execução (apenas) após um trecho ser escrito, para que a lista negra seja incorporada na próxima imagem de inicialização. As entradas de kernel mais antigas mantêm seu initramfs original como fallback. ## Use `-fix` apenas após uma execução somente de verificação **Sempre execute o vcheck sem `-fix` primeiro.** Leia o relatório e confirme que os módulos afetados são seguros para desabilitar neste host antes de executar novamente com `-fix`. Desabilitar módulos do kernel dos quais cargas de trabalho legítimas dependem pode afetar usuários e quebrar aplicações. Em particular: - Trate `-fix` como seguro **apenas** quando nenhum dos módulos afetados estiver atualmente carregado — ou seja, cada módulo é relatado como `mitigated` ou `module not blacklisted` (sem linhas `VULNERABLE` ou `blacklisted but currently loaded`). Um módulo carregado quase sempre significa que _algo no host está usando-o ativamente_; verifique isso antes de colocar na lista negra. - Os módulos IPsec (`esp4`, `esp6`, `ipcomp4`, `ipcomp6`, `xfrm_user`) são necessários para qualquer implantação IPsec/strongSwan/WireGuard-over-IPsec/IKE. Os módulos `ipcomp4`/`ipcomp6` implementam compressão de carga útil IPComp e podem ser auto-negociados como parte de uma SA IPsec mesmo quando não configurados explicitamente. Não coloque nenhum deles na lista negra em um gateway VPN, endpoint IPsec ou em qualquer lugar onde `ip xfrm policy` retorne regras. Note que o módulo de framework `xfrm_algo` está intencionalmente **não** nesta lista — de acordo com orientações de fornecedores (Red Hat, Ubuntu, AWS), bloquear os módulos de protocolo ESP e IPComp mais a interface de configuração netlink `xfrm_user` é suficiente, e colocar `xfrm_algo` na lista negra quebraria todas as outras transformações xfrm sem benefício extra. - Os módulos RxRPC (`rxrpc`, `kafs`) são necessários para qualquer host que monte sistemas de arquivos AFS. Desabilitá-los quebrará essas montagens na próxima inicialização. - `algif_aead` expõe criptografia do kernel através da família de sockets `AF_ALG`. Raramente é usado diretamente por código de aplicação, mas verifique listando sockets ativos (`ss -p --af-alg`) e verificando consumidores no espaço de usuário antes de colocar na lista negra. Os trechos de lista negra que o vcheck escreve só entram em vigor no momento do carregamento do módulo (tipicamente na próxima inicialização, ou `modprobe -r <módulo>` enquanto o sistema está ocioso). Um módulo que já está _carregado_ continuará em execução mesmo após `-fix` — o vcheck relatará isso como `blacklisted but currently loaded; run 'modprobe -r' or reboot`. Passar `-unload` junto com `-fix` faz com que o vcheck execute `modprobe -r` para módulos afetados carregados após escrever os trechos de lista negra. Use isso apenas quando tiver confirmado que os módulos são seguros para remover do kernel em execução. Passar `-rebuild-initramfs` com `-fix` regenera o initramfs para o **kernel atualmente em execução apenas** (`update-initramfs -u -k $(uname -r)` no Debian/Ubuntu, `dracut -f --kver $(uname -r)` no RHEL/Fedora). Outros kernels instalados mantêm seu initramfs existente inalterado, então se algo der errado após a reinicialização, você pode escolher uma entrada de kernel mais antiga no menu de inicialização e se recuperar. Futuras instalações de kernel reconstroem seu próprio initramfs a partir do estado atual de `/etc/modprobe.d/`, então a lista negra se propaga automaticamente sem precisar executar o vcheck novamente. Se nem `update-initramfs` nem `dracut` estiverem presentes (ex.: Arch, Alpine, imagens imutáveis), o vcheck avisa e continua — reconstrua manualmente com a ferramenta da distribuição antes de reinicializar. A reconstrução pode levar vários minutos (especialmente `dracut` em hosts com muitos drivers), o que excederia o `-command-timeout` diagnóstico. Ela é executada sob seu próprio `-initramfs-timeout` (padrão `10m`) para que a reconstrução tenha o espaço necessário enquanto as verificações rápidas mantêm seu orçamento apertado. Aumente `-initramfs-timeout` para hardware lento, ou passe `0` para desabilitar o timeout completamente. Durante comandos remotos de longa duração, o vcheck envia solicitações SSH keepalive a cada `30s` por padrão para evitar que timers ociosos de NAT/firewall derrubem a conexão. Ajuste isso com `-ssh-keepalive`, ou passe `0` para desabilitar. ## Instalação **Homebrew (macOS):** ```bash brew install --cask krisiasty/tap/vcheck ``` **Binários pré-compilados** para Linux, macOS e Windows são publicados na [página de releases](https://github.com/krisiasty/vcheck/releases). **A partir do código fonte** (requer Go 1.26+): ```bash go install github.com/krisiasty/vcheck@latest ``` ## Uso ```text vcheck -host HOST [flags] ``` | Flag | Padrão | Descrição | | -------------------- | ------------ | --------------------------------------------------------------------------------------------- | | `-host` | _(obrigatório)_ | Host remoto | | `-user` | `$USER` | Usuário remoto | | `-port` | `22` | Porta SSH remota | | `-agent` | `true` | Usar agente SSH para autenticação | | `-identity` | _(vazio)_ | Caminho para um arquivo de chave privada (solicita senha se criptografado) | | `-password` | `false` | Solicitar uma senha SSH | | `-insecure` | `false` | Aceitar chaves de host ainda não registradas em `known_hosts`; incompatibilidades com uma chave registrada ainda falham | | `-fix` | `false` | Escrever trechos `/etc/modprobe.d` para módulos que ainda não estão na lista negra | | `-unload` | `false` | Com `-fix`, descarregar módulos afetados após colocá-los na lista negra | | `-rebuild-initramfs` | `false` | Com `-fix`, reconstruir initramfs para o kernel em execução apenas (`update-initramfs` ou `dracut`) | | `-skip-logs` | `false` | Pular verificações do histórico de logs do kernel | | `-timeout` | `15s` | Timeout de conexão SSH | | `-ssh-keepalive` | `30s` | Intervalo de keepalive SSH (`0` desabilita) | | `-command-timeout` | `30s` | Timeout de comando remoto (`0` desabilita) | | `-initramfs-timeout` | `10m` | Timeout para a etapa de reconstrução do initramfs (`0` desabilita); usado apenas com `-rebuild-initramfs` | | `-debug` | `false` | Aumentar verbosidade do log | | `-version` | `false` | Mostrar versão e sair | Pelo menos um entre `-agent`, `-identity` ou `-password` deve produzir um método de autenticação utilizável. Os métodos são tentados na ordem listada. Sudo é necessário no alvo. Se sudo sem senha estiver configurado, a ferramenta prossegue silenciosamente; caso contrário, solicita uma senha uma vez (a entrada fica oculta) e a fornece via `sudo -S` para cada comando subsequente. ## Códigos de saída | Código | Significado | | ------ | ----------------------------------------------------------------------------------- | | `0` | Todos os módulos afetados na lista negra, descarregados, não embutidos e inativos | | `1` | Erro de uso | | `2` | Falha na conexão SSH | | `3` | Falha na autenticação sudo | | `4` | Um ou mais módulos não na lista negra (sem exposição atual) | | `5` | Um ou mais módulos atualmente carregados, embutidos no kernel, ou em uso ativo | | `99` | Falha interna/de verificação | ## Exemplo de saída ### Host completamente mitigado ```console $ vcheck -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF mitigated cve=CVE-2026-31431 module=algif_aead INF mitigated cve=CVE-2026-43284 module=esp4 INF mitigated cve=CVE-2026-43284 module=esp6 INF mitigated cve=CVE-2026-43284 module=ipcomp4 INF mitigated cve=CVE-2026-43284 module=ipcomp6 INF mitigated cve=CVE-2026-43284 module=xfrm_user INF mitigated cve=CVE-2026-43500 module=rxrpc INF mitigated cve=CVE-2026-43500 module=kafs ``` ### Não mitigado e parcialmente carregado — verificação simples ```console $ vcheck -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF mitigated cve=CVE-2026-31431 module=algif_aead ERR VULNERABLE cve=CVE-2026-43284 module=esp4 loaded=true ERR module not blacklisted cve=CVE-2026-43284 module=esp6 ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp4 ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp6 ERR module not blacklisted cve=CVE-2026-43284 module=xfrm_user ERR module not blacklisted cve=CVE-2026-43500 module=rxrpc ERR module not blacklisted cve=CVE-2026-43500 module=kafs ``` ### Mesmo host com `-fix` — primeira execução ```console $ vcheck -fix -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF findings before fix INF mitigated cve=CVE-2026-31431 module=algif_aead ERR VULNERABLE cve=CVE-2026-43284 module=esp4 loaded=true ERR module not blacklisted cve=CVE-2026-43284 module=esp6 ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp4 ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp6 ERR module not blacklisted cve=CVE-2026-43284 module=xfrm_user ERR module not blacklisted cve=CVE-2026-43500 module=rxrpc ERR module not blacklisted cve=CVE-2026-43500 module=kafs INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43284-disable.conf modules="[esp4 esp6 ipcomp4 ipcomp6 xfrm_user]" INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43500-disable.conf modules="[rxrpc kafs]" INF re-scanning after fix snippets_written=2 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF findings after fix INF mitigated cve=CVE-2026-31431 module=algif_aead ERR blacklisted but currently loaded; run 'modprobe -r' or reboot cve=CVE-2026-43284 module=esp4 INF mitigated cve=CVE-2026-43284 module=esp6 INF mitigated cve=CVE-2026-43284 module=ipcomp4 INF mitigated cve=CVE-2026-43284 module=ipcomp6 INF mitigated cve=CVE-2026-43284 module=xfrm_user INF mitigated cve=CVE-2026-43500 module=rxrpc INF mitigated cve=CVE-2026-43500 module=kafs ``` A lista negra está em vigor, mas `esp4` já estava carregado no kernel antes do trecho ser escrito. Reinicialize ou execute `sudo modprobe -r esp4` no alvo para limpá-lo completamente. ### Segunda execução — esp4 ainda carregado ```console $ vcheck -fix -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF findings before fix INF mitigated cve=CVE-2026-31431 module=algif_aead ERR blacklisted but currently loaded; run 'modprobe -r' or reboot cve=CVE-2026-43284 module=esp4 INF mitigated cve=CVE-2026-43284 module=esp6 INF mitigated cve=CVE-2026-43284 module=ipcomp4 INF mitigated cve=CVE-2026-43284 module=ipcomp6 INF mitigated cve=CVE-2026-43284 module=xfrm_user INF mitigated cve=CVE-2026-43500 module=rxrpc INF mitigated cve=CVE-2026-43500 module=kafs INF fix: nothing to do — all affected modules already blacklisted ``` ### Terceira execução — após `modprobe -r esp4` ```console $ vcheck -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF mitigated cve=CVE-2026-31431 module=algif_aead INF mitigated cve=CVE-2026-43284 module=esp4 INF mitigated cve=CVE-2026-43284 module=esp6 INF mitigated cve=CVE-2026-43284 module=ipcomp4 INF mitigated cve=CVE-2026-43284 module=ipcomp6 INF mitigated cve=CVE-2026-43284 module=xfrm_user INF mitigated cve=CVE-2026-43500 module=rxrpc INF mitigated cve=CVE-2026-43500 module=kafs ``` ### Com `-rebuild-initramfs` ```console $ vcheck -fix -rebuild-initramfs -host host.example.com -identity ~/.ssh/id_ed25519 ... INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43284-disable.conf modules="[esp4 esp6 ipcomp4 ipcomp6 xfrm_user]" INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43500-disable.conf modules="[rxrpc kafs]" INF rebuilding initramfs for running kernel timeout=10m0s INF initramfs rebuilt for running kernel tool=update-initramfs INF re-scanning after fix snippets_written=2 ... ``` Apenas o initramfs do kernel em execução é reconstruído. Outros kernels instalados mantêm seu initramfs existente, então uma entrada mais antiga no menu de inicialização permanece como um fallback funcional se o novo initramfs causar problemas. Em um host sem `update-initramfs` nem `dracut`, o vcheck registra `WRN no supported initramfs tool found ...` e continua. ### Primeira vez no host — `-insecure` ```console $ vcheck -insecure -host host.example.com -identity ~/.ssh/id_ed25519 WRN host key not in known_hosts; accepting due to -insecure host=host.example.com:22 remote=192.0.2.42:22 fingerprint=SHA256:AAAAEXAMPLEfingerPrint000000000000000000000 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" ... ``` `-insecure` aceita hosts que ainda não estão em `known_hosts`. Se um host _já_ estiver registrado e apresentar uma chave diferente, a conexão ainda falha — a bandeira é apenas uma substituição de "primeiro contato", não uma forma de suprimir avisos de man-in-the-middle em um host conhecido. ## Detalhes de detecção - **Carregado:** `lsmod` é obtido uma vez e os nomes dos módulos são comparados com a primeira coluna. - **Embutido:** `/lib/modules/$(uname -r)/modules.builtin` e `/sys/module` são verificados porque trechos modprobe não podem desabilitar código compilado no kernel em execução. - **Na lista negra:** cada arquivo em `/etc/modprobe.d/` é pesquisado (`grep -rE`) por uma diretiva `install <module> /bin/false` — a mesma forma que o vcheck escreve com `-fix`. Outras formas de desabilitar (ex.: `blacklist`) não são reconhecidas. - **Atividade passada:** `journalctl -k` é consultado primeiro, com fallback para `/var/log/kern.log`; as últimas cinco linhas correspondentes por módulo são mantidas. Passe `-skip-logs` para pular esta etapa. - **Sockets ativos (apenas `algif_aead`):** `ss -p --af-alg` lista sockets `AF_ALG` abertos; qualquer saída diferente do cabeçalho conta como uso ativo. Todos os comandos são executados via `sudo` e são limitados por `-command-timeout` — acesso privilegiado é necessário para ler `/var/log/kern.log`, listar sockets `AF_ALG` e escrever em `/etc/modprobe.d/`. Com `-unload`, acesso privilegiado também é necessário para executar `modprobe -r`. Com `-rebuild-initramfs`, o vcheck executa `update-initramfs -u -k $(uname -r)` (Debian/Ubuntu) ou `dracut -f --kver $(uname -r)` (RHEL/Fedora), que também precisam de root.