Pourquoi on a créé kmod-guard - moins de modules noyau, moins d'exposition

Copy Fail, Dirty Frag, VsockDrop, OVSwrap, DiagSpill et bien d'autres : en quelques mois, des dizaines de failles du noyau Linux, presque toutes dans des modules que nos serveurs n'utilisaient pas. Voici pourquoi on bloque maintenant ces modules par défaut.

2026-09-24

Pourquoi on a créé kmod-guard - moins de modules noyau, moins d'exposition

Pourquoi on a créé kmod-guard - moins de modules noyau, moins d'exposition - bannière

Depuis le printemps 2026, les failles du noyau Linux s'enchaînent à un rythme inhabituel : plus de 6 500 CVE du noyau publiées depuis janvier, selon LinuxCVETracker. La plupart passent inaperçues, mais une série d'élévations de privilèges a eu droit à un nom, un exploit public et une course aux correctifs : Copy Fail, Dirty Frag, VsockDrop, OVSwrap, PPPoEject, DiagSpill, DirtyAH6, TUNderflow… En les regardant de près, on a remarqué qu'elles avaient presque toutes un point en commun : le code vulnérable se trouvait dans un module que le serveur n'utilisait pas, mais qu'un utilisateur sans privilèges pouvait faire charger.

C'est ce constat qui nous a amenés à écrire kmod-guard, un petit outil open source qui bloque le chargement de ces modules avant la prochaine faille, plutôt qu'après.

Une faille après l'autre, le même schéma

Voici une partie des failles publiées entre avril et septembre 2026. La dernière colonne indique si la liste par défaut de kmod-guard bloque le module en cause sur un serveur qui ne l'utilise pas déjà (vérifié sur un noyau 6.18).

Faille CVE Module(s) en cause Impact Bloqué par défaut
Copy Fail CVE-2026-31431 algif_aead (AF_ALG) root oui
Dirty Frag CVE-2026-43284, CVE-2026-43500 esp4, esp6, rxrpc root oui
pedit COW CVE-2026-46331 act_pedit (contrôle du trafic) root oui
VsockDrop CVE-2026-53365 vsock, vsock_loopback root oui
OVSwrap CVE-2026-64531 openvswitch root oui
Zapscape CVE-2026-64561 kvm évasion d'une VM vers l'hôte non (par choix)
PPPoEject CVE-2026-68121 pppoe root oui
RtabRace CVE-2026-68138 cls_flower, act_police plantage de l'hôte oui
bridge-stp-uaf CVE-2026-72389 bridge root non (par choix)
DiagSpill CVE-2026-74469 sctp, sctp_diag root oui
DirtyAH6 CVE-2026-80844 ah6 (IPsec) root oui
TUNderflow CVE-2026-81000 tun root oui

Sur un serveur web typique, la plupart de ces modules ne sont jamais chargés : on n'y fait pas d'IPsec, pas d'AFS, pas de SCTP, pas de PPPoE, pas d'Open vSwitch, et on n'y configure pas de filtres de trafic. Pourtant, ils sont installés avec le noyau et le noyau les charge automatiquement dès qu'un programme les demande :

  • ouvrir un socket AF_ALG, AF_RXRPC, AF_VSOCK, AF_PPPOX ou SCTP suffit pour charger le module correspondant;
  • créer un espace de noms utilisateur (unshare -Urn) donne à un utilisateur ordinaire les droits d'administration réseau dans son propre espace, et donc la possibilité de charger act_pedit, cls_flower, openvswitch, ah6 ou tun.

Autrement dit, un compte FTP compromis, un site WordPress piraté ou un conteneur mal isolé peut faire entrer dans le noyau du code qui n'avait rien à y faire.

La mitigation classique arrive toujours en retard

Pour chacune de ces failles, les avis de sécurité (CERT-EU, Ubuntu, Red Hat, CloudLinux, TuxCare) ont recommandé, en attendant un noyau corrigé, la même mesure temporaire :

echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf

Une ligne par module, ajoutée après la divulgation. Entre le moment où l'exploit est public et celui où la ligne est déployée sur chaque serveur, la fenêtre reste ouverte. Et ce n'est qu'une mesure temporaire : il faut ensuite installer le noyau corrigé et redémarrer, ce qui n'est pas toujours possible le jour même en production.

Une douzaine de failles en six mois, une douzaine de fois le même exercice. Et chaque fois, la même question : pourquoi ce module était-il chargeable sur ce serveur?

Inverser la logique : bloquer ce qui n'est pas utilisé

kmod-guard applique la mitigation classique à tous les modules d'un coup, avant qu'une faille soit connue. Le principe :

  1. Il garde tout ce que le serveur utilise : les modules chargés actuellement, tous ceux qu'il a déjà vus chargés sur cet hôte, une liste d'autorisation, et toutes leurs dépendances.
  2. Il bloque le reste avec une ligne install dans /etc/modprobe.d/kmod-guard.conf.
  3. Chaque tentative bloquée est journalisée dans syslog, avec le processus à l'origine quand il est identifiable.

La liste par défaut garde les pilotes matériels, les systèmes de fichiers courants et les modules netfilter (iptables, nftables, ipset) utilisés par les pare-feu comme CSF, fail2ban ou Imunify360. Ce qui reste bloqué, ce sont les familles de sockets peu courantes, les ordonnanceurs et filtres de trafic, AF_ALG, les périphériques réseau virtuels et les systèmes de fichiers réseau ou anciens : exactement là où se trouvaient la plupart des failles de 2026.

Sur un serveur qui n'utilisait pas déjà les modules touchés, kmod-guard aurait empêché un utilisateur ordinaire d'atteindre dix des douze failles du tableau (tant que ces modules ne sont pas compilés directement dans le noyau).

Les deux autres, Zapscape (kvm) et bridge-stp-uaf (bridge), ne sont pas bloquées par défaut, et c'est un choix. Ces deux modules font partie d'une chaîne de dépendances : kvm est autorisé avec les modules du processeur (kvm_intel, kvm_amd), et bridge est requis par des modules netfilter autorisés (nft_meta_bridge, nf_conntrack_bridge). Les bloquer risquerait de briser un pare-feu ou un hyperviseur. Entre une protection de plus et un risque de panne en production, la liste par défaut choisit de ne pas causer de problème. Sur un serveur qui n'en a pas besoin, rien n'empêche de resserrer la liste d'autorisation.

Ce qu'on voulait éviter

Un outil de sécurité qui casse la production finit désactivé. On a donc posé quelques règles :

  • Aucun redémarrage, rien n'est déchargé. Supprimer le fichier annule tout instantanément.
  • Un module chargé n'est jamais bloqué. L'outil refuse d'écrire une liste qui en bloquerait un.
  • La liste ne fait que grandir du côté « autorisé ». Un module vu une fois chargé reste permis, même après un redémarrage.
  • Premier passage différé. L'outil attend 30 minutes après le démarrage pour ne pas prendre sa photo en plein démarrage des services.
  • Nouveaux noyaux protégés. Les dépendances sont calculées pour chaque noyau installé, et les crochets initramfs retirent la liste des images de démarrage, pour qu'un nouveau noyau puisse toujours charger les pilotes du disque racine.
  • Un seul script shell POSIX, sans dépendance au-delà de coreutils, diffutils, awk et kmod. Les tests roulent en intégration continue sur Debian, Ubuntu, AlmaLinux 8, Rocky Linux 9 et Alpine.

Ce que kmod-guard ne remplace pas

kmod-guard n'est pas infaillible. Il réduit ce qu'un utilisateur sans privilèges peut faire entrer dans le noyau, mais une chaîne d'attaque peut passer par un module qu'il garde volontairement, comme bridge ou kvm, ou par un module que le serveur utilise réellement. Ce n'est pas une frontière contre root, qui peut toujours charger un module avec insmod ou modprobe --ignore-install. Il ne touche pas non plus au code compilé directement dans le noyau.

Il ne remplace donc pas :

  • les mises à jour du noyau, qu'on continue d'appliquer dès qu'elles sont disponibles;
  • la restriction des espaces de noms utilisateur (user.max_user_namespaces, AppArmor sur Ubuntu 24.04). Plusieurs failles du tableau passent par là, et c'est la mitigation principale sur un hôte qui a besoin des modules touchés, comme un hyperviseur Proxmox (contrôle du trafic, ponts, parfois Open vSwitch);
  • la désactivation d'io_uring (kernel.io_uring_disabled) là où il n'est pas utilisé.

C'est une couche de plus, qui réduit la surface d'attaque en permanence au lieu de la colmater faille par faille.

Pensé pour un parc de serveurs

kmod-guard a été conçu pour être déployé par la gestion de configuration : un fichier d'autorisation géré centralement, des exemples prêts pour Proxmox VE, Docker Swarm et WireGuard, et un minuteur systemd qui régénère la liste chaque jour. Les tentatives bloquées sont journalisées dans syslog (journalctl -t kmod-guard).

Quand une nouvelle faille sort, une seule commande indique si un serveur est exposé :

sudo kmod-guard generate --dry-run --probe "esp4 esp6 rxrpc"
# probe_blocked=esp4 esp6 rxrpc

Les modules listés dans probe_blocked ne peuvent pas être chargés sur ce serveur. Ceux qui n'y apparaissent pas sont utilisés ou autorisés : c'est là qu'il faut appliquer le correctif en priorité.

Le code est public, sous licence MIT, et s'inspire de modulejail de Jasper Nuyens, auquel il ajoute la résolution des dépendances, la mémoire des modules déjà vus et les autorisations par motif et par chemin.

Vous voulez savoir si vos serveurs étaient exposés à ces failles, ou faire durcir votre infrastructure? Sécuriser un serveur · Surveillance 24/7 · Nous écrire

Audit gratuit · 24 h

Votre site est lent ? Recevez un diagnostic gratuit en 24 h.

Triage gratuit sans engagement. Un expert vous répond en moins de 8 h ouvrables.