
Outil de détection et d'atténuation des vulnérabilités pour les bugs Copy Fail et Dirty Frag (CVE-2026-31431, CVE-2026-43284, CVE-2026-43500)
# vcheck Auditer un hôte Linux distant via SSH pour les vulnérabilités des modules noyau Copy Fail et Dirty Frag et, optionnellement, appliquer des atténuations : | CVE | Nom | Modules affectés | | -------------- | ------------------ | ------------------------------------------------- | | 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` | Pour chaque module affecté, vcheck indique s'il est actuellement chargé, intégré au noyau en cours d'exécution, s'il a des traces passées dans les journaux du noyau, s'il a des sockets `AF_ALG` actives (Copy Fail uniquement), et s'il est déjà mis sur liste noire dans `/etc/modprobe.d/`. Avec `-fix`, vcheck signale l'état initial, écrit un fragment `cve-XXXX-XXXXX-disable.conf` pour tout module qui n'est pas encore sur liste noire, puis relance les vérifications et signale l'état final. Avec `-fix -unload`, vcheck tente également de décharger les modules affectés qui étaient chargés avant le correctif, puis utilise l'analyse finale pour vérifier s'ils sont toujours chargés. Avec `-fix -rebuild-initramfs`, vcheck reconstruit l'initramfs pour le noyau en cours d'exécution (uniquement) après avoir écrit un fragment, de sorte que la liste noire soit intégrée dans l'image de démarrage suivante. Les entrées de noyau plus anciennes conservent leur initramfs d'origine comme solution de repli. ## Utiliser `-fix` uniquement après une exécution sans correction **Exécutez toujours vcheck sans `-fix` d'abord.** Lisez le rapport et confirmez que les modules affectés peuvent être désactivés en toute sécurité sur cet hôte avant de relancer avec `-fix`. La désactivation de modules noyau dont dépendent des charges de travail légitimes peut affecter les utilisateurs et casser des applications. En particulier : - Considérez `-fix` comme sûr **uniquement** lorsque aucun des modules affectés n'est actuellement chargé — c'est-à-dire que chaque module est signalé comme `mitigé` ou `module non blacklisté` (aucune ligne `VULNÉRABLE` ou `blacklisté mais actuellement chargé`). Un module chargé signifie presque toujours que _quelque chose sur l'hôte l'utilise activement_ ; vérifiez cela avant de mettre sur liste noire. - Les modules IPsec (`esp4`, `esp6`, `ipcomp4`, `ipcomp6`, `xfrm_user`) sont nécessaires pour tout déploiement IPsec/strongSwan/WireGuard-over-IPsec/IKE. Les modules `ipcomp4`/`ipcomp6` implémentent la compression de charge utile IPComp et peuvent être auto-négociés dans le cadre d'une SA IPsec même lorsqu'ils ne sont pas explicitement configurés. Ne mettez aucun d'entre eux sur liste noire sur une passerelle VPN, un point de terminaison IPsec ou partout où `ip xfrm policy` renvoie des règles. Notez que le module framework `xfrm_algo` n'est intentionnellement **pas** dans cette liste — selon les directives des fournisseurs (Red Hat, Ubuntu, AWS), bloquer les modules de protocole ESP et IPComp ainsi que l'interface de configuration netlink `xfrm_user` est suffisant, et blacklister `xfrm_algo` casserait toutes les autres transformations xfrm pour aucun bénéfice supplémentaire. - Les modules RxRPC (`rxrpc`, `kafs`) sont nécessaires pour tout hôte qui monte des systèmes de fichiers AFS. Leur désactivation cassera ces montages au prochain démarrage. - `algif_aead` expose la crypto du noyau via la famille de sockets `AF_ALG`. Il est rarement utilisé directement par le code applicatif, mais vérifiez en listant les sockets actives (`ss -p --af-alg`) et en consultant les consommateurs espace utilisateur avant de le blacklister. Les fragments de liste noire écrits par vcheck ne prennent effet qu'au moment du chargement du module (généralement au prochain démarrage, ou avec `modprobe -r <module>` lorsque le système est inactif). Un module _déjà chargé_ continuera de fonctionner même après `-fix` — vcheck le signalera comme `blacklisté mais actuellement chargé ; exécutez 'modprobe -r' ou redémarrez`. Passer `-unload` avec `-fix` demande à vcheck d'exécuter `modprobe -r` pour les modules affectés chargés après avoir écrit les fragments de liste noire. Utilisez-le uniquement lorsque vous avez confirmé que les modules peuvent être retirés du noyau en cours d'exécution en toute sécurité. Passer `-rebuild-initramfs` avec `-fix` régénère l'initramfs pour le **noyau en cours d'exécution uniquement** (`update-initramfs -u -k $(uname -r)` sur Debian/Ubuntu, `dracut -f --kver $(uname -r)` sur RHEL/Fedora). Les autres noyaux installés conservent leur initramfs existant intact, donc si quelque chose se passe mal après le redémarrage, vous pouvez choisir une entrée de noyau plus ancienne dans le menu de démarrage et récupérer. Les futures installations de noyau reconstruisent leur propre initramfs à partir de l'état actuel de `/etc/modprobe.d/`, donc la liste noire se propage automatiquement sans relancer vcheck. Si ni `update-initramfs` ni `dracut` n'est présent (par exemple Arch, Alpine, images immuables), vcheck émet un avertissement et continue — reconstruisez manuellement avec l'outil de la distribution avant de redémarrer. La reconstruction peut prendre plusieurs minutes (surtout `dracut` sur les hôtes avec de nombreux pilotes), ce qui dépasserait le `-command-timeout` de diagnostic. Elle s'exécute sous son propre `-initramfs-timeout` (par défaut `10m`) de sorte que la reconstruction dispose de l'espace nécessaire tandis que les vérifications rapides conservent leur budget serré. Augmentez `-initramfs-timeout` pour le matériel lent, ou passez `0` pour désactiver complètement le délai d'attente. Pendant les commandes distantes de longue durée, vcheck envoie des requêtes keepalive SSH toutes les `30s` par défaut pour éviter que les temporisateurs d'inactivité NAT/pare-feu ne coupent la connexion. Ajustez cela avec `-ssh-keepalive`, ou passez `0` pour le désactiver. ## Installation **Homebrew (macOS) :** ```bash brew install --cask krisiasty/tap/vcheck ``` **Binaires pré-compilés** pour Linux, macOS et Windows sont publiés sur la [page des versions](https://github.com/krisiasty/vcheck/releases). **Depuis les sources** (nécessite Go 1.26+) : ```bash go install github.com/krisiasty/vcheck@latest ``` ## Utilisation ```text vcheck -host HOST [flags] ``` | Indicateur | Par défaut | Description | | -------------------- | ---------- | --------------------------------------------------------------------------------------------- | | `-host` | _(requis)_ | Hôte distant | | `-user` | `$USER` | Utilisateur distant | | `-port` | `22` | Port SSH distant | | `-agent` | `true` | Utiliser l'agent SSH pour l'authentification | | `-identity` | _(vide)_ | Chemin vers un fichier de clé privée (demande la phrase de passe si chiffrée) | | `-password` | `false` | Demander un mot de passe SSH | | `-insecure` | `false` | Accepter les clés d'hôte non encore enregistrées dans `known_hosts` ; les discordances avec une clé enregistrée échouent toujours | | `-fix` | `false` | Écrire des fragments dans `/etc/modprobe.d` pour les modules qui ne sont pas déjà sur liste noire | | `-unload` | `false` | Avec `-fix`, décharger les modules affectés après les avoir blacklistés | | `-rebuild-initramfs` | `false` | Avec `-fix`, reconstruire l'initramfs pour le noyau en cours d'exécution uniquement (`update-initramfs` ou `dracut`) | | `-skip-logs` | `false` | Ignorer les vérifications de l'historique des journaux du noyau | | `-timeout` | `15s` | Délai d'attente de connexion SSH | | `-ssh-keepalive` | `30s` | Intervalle keepalive SSH (`0` désactive) | | `-command-timeout` | `30s` | Délai d'attente des commandes distantes (`0` désactive) | | `-initramfs-timeout` | `10m` | Délai d'attente pour l'étape de reconstruction de l'initramfs (`0` désactive) ; utilisé uniquement avec `-rebuild-initramfs` | | `-debug` | `false` | Augmenter la verbosité des journaux | | `-version` | `false` | Afficher la version et quitter | Au moins l'un de `-agent`, `-identity` ou `-password` doit produire une méthode d'authentification utilisable. Les méthodes sont essayées dans l'ordre indiqué. Sudo est requis sur la cible. Si sudo sans mot de passe est configuré, l'outil procède silencieusement ; sinon, il demande une fois un mot de passe (la saisie est masquée) et le transmet via `sudo -S` pour chaque commande suivante. ## Codes de sortie | Code | Signification | | ---- | ------------------------------------------------------------------------------------- | | `0` | Tous les modules affectés sont blacklistés, déchargés, non intégrés au noyau et inactifs | | `1` | Erreur d'utilisation | | `2` | Échec de la connexion SSH | | `3` | Échec de l'authentification sudo | | `4` | Un ou plusieurs modules non blacklistés (aucune exposition actuelle) | | `5` | Un ou plusieurs modules actuellement chargés, intégrés au noyau ou activement utilisés | | `99` | Échec interne/de vérification | ## Exemple de sortie ### Hôte entièrement atténué ```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 ``` ### Non atténué et partiellement chargé — vérification simple ```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 ``` ### Même hôte avec `-fix` — première exécution ```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 ``` La liste noire est en place, mais `esp4` était déjà chargé dans le noyau avant l'écriture du fragment. Redémarrez ou exécutez `sudo modprobe -r esp4` sur la cible pour le vider entièrement. ### Deuxième exécution — esp4 toujours chargé ```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 ``` ### Troisième exécution — aprè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 ``` ### Avec `-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 ... ``` Seul l'initramfs du noyau en cours d'exécution est reconstruit. Les autres noyaux installés conservent leur initramfs existant, donc une entrée plus ancienne dans le menu de démarrage reste un repli fonctionnel si le nouvel initramfs pose problème. Sur un hôte sans `update-initramfs` ni `dracut`, vcheck enregistre `WRN no supported initramfs tool found ...` et continue. ### Premier hôte — `-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` accepte les hôtes qui ne sont pas encore dans `known_hosts`. Si un hôte _est_ déjà enregistré et présente une clé différente, la connexion échoue toujours — l'indicateur n'est qu'une dérogation de "premier contact", pas un moyen de supprimer les avertissements d'homme du milieu sur un hôte connu. ## Détails de détection - **Chargé :** `lsmod` est récupéré une fois et les noms de modules sont comparés à la première colonne. - **Intégré :** `/lib/modules/$(uname -r)/modules.builtin` et `/sys/module` sont vérifiés car les fragments modprobe ne peuvent pas désactiver le code compilé dans le noyau en cours d'exécution. - **Blacklisté :** chaque fichier sous `/etc/modprobe.d/` est recherché (`grep -rE`) pour une directive `install <module> /bin/false` — la même forme que vcheck écrit avec `-fix`. D'autres formes de désactivation (par exemple `blacklist`) ne sont pas reconnues. - **Activité passée :** `journalctl -k` est consulté en premier, avec un repli vers `/var/log/kern.log` ; les cinq dernières lignes correspondantes par module sont conservées. Passez `-skip-logs` pour ignorer cette étape. - **Sockets actives (`algif_aead` uniquement) :** `ss -p --af-alg` liste les sockets `AF_ALG` ouvertes ; toute sortie autre que l'en-tête est considérée comme une utilisation active. Toutes les commandes sont exécutées via `sudo` et sont limitées par `-command-timeout` — un accès privilégié est requis pour lire `/var/log/kern.log`, lister les sockets `AF_ALG` et écrire sous `/etc/modprobe.d/`. Avec `-unload`, un accès privilégié est également requis pour exécuter `modprobe -r`. Avec `-rebuild-initramfs`, vcheck exécute `update-initramfs -u -k $(uname -r)` (Debian/Ubuntu) ou `dracut -f --kver $(uname -r)` (RHEL/Fedora), qui nécessitent aussi les droits root.