kmod-guard - bloquer les modules noyau inutilisés

Installer et utiliser kmod-guard, un outil open source de webO3 qui bloque le chargement à la demande des modules noyau Linux qu'un serveur n'utilise pas.

kmod-guard - bloquer les modules noyau inutilisés

Installer et utiliser kmod-guard, un outil open source de webO3 qui bloque le chargement à la demande des modules noyau Linux qu'un serveur n'utilise pas.

Introduction

Plusieurs failles d'élévation de privilèges du noyau Linux se trouvent dans des modules qu'un utilisateur sans privilèges peut faire charger à la demande : une famille de sockets peu courante (sctp, tipc, vsock), une action de contrôle du trafic, une expression netfilter depuis un espace de noms utilisateur, un système de fichiers via mount(2), un algorithme AF_ALG. En 2026, Copy Fail, Dirty Frag, VsockDrop, OVSwrap, PPPoEject, RtabRace, DiagSpill, DirtyAH6, TUNderflow et plusieurs autres ont suivi ce schéma.

La mitigation habituelle consiste à ajouter une ligne install <module> /bin/false par CVE, après coup. kmod-guard le fait pour tous les modules d'un coup : tout ce qui n'est ni utilisé ni autorisé reçoit une ligne install dans /etc/modprobe.d/kmod-guard.conf.

  • Aucun redémarrage, rien n'est déchargé. Supprimer le fichier annule tout instantanément.
  • Un module chargé n'est jamais bloqué.
  • Les pilotes matériels restent chargeables (par défaut).

Pour le contexte et les raisons derrière l'outil : Pourquoi on a créé kmod-guard.

Prérequis

  • Linux avec systemd (le minuteur est optionnel)
  • coreutils, diffutils, awk et kmod
  • Accès root

Fonctionnement

garder  = modules chargés maintenant                   (/proc/modules)
        + tous les modules déjà vus chargés sur l'hôte  (/var/lib/kmod-guard/learned)
        + entrées d'autorisation                        (/etc/kmod-guard/allow.d/*.conf)
        + leurs dépendances                             (modules.dep, softdep, alias) pour chaque noyau installé
bloquer = modules du noyau en cours - garder

Chaque module bloqué reçoit la ligne install <module> /usr/local/sbin/kmod-guard blocked <module>. Quand quelque chose tente de le charger, modprobe exécute cette commande à la place : la tentative est journalisée dans syslog et le module reste déchargé.

L'ensemble « garder » ne fait que grandir. Relancer generate (manuellement, par minuteur ou par la gestion de configuration) ne peut bloquer que des modules nouveaux pour le noyau en cours.

Installation

git clone https://github.com/webo3/kmod-guard.git
cd kmod-guard
sudo make install

Le script est installé dans /usr/local/sbin/kmod-guard. Ce chemin est fixe, car les lignes install générées l'appellent. L'installation ajoute aussi :

  • la liste d'autorisation par défaut dans /etc/kmod-guard/allow.d/00-managed.conf, si le fichier n'existe pas déjà;
  • le crochet initramfs pour initramfs-tools ou dracut;
  • un service et un minuteur systemd, non activés.

Premier lancement

# Voir ce qui serait bloqué
sudo kmod-guard generate --dry-run

# Écrire la liste
sudo kmod-guard generate

# Régénérer chaque jour
sudo systemctl daemon-reload
sudo systemctl enable --now kmod-guard.timer

Lancez le premier generate une fois que le serveur roule depuis assez longtemps pour que ses services aient chargé leurs modules. L'outil refuse de s'exécuter pendant les 30 premières minutes suivant le démarrage, sauf avec --force.

generate affiche un résumé clé=valeur (nombre de modules gardés et bloqués, nouveaux modules bloqués ou autorisés) qui se termine par result=changed, unchanged, skipped ou disabled. Avec --dry-run, il se termine plutôt par result=dry-run et would_change=yes|no.

Listes d'autorisation

Les fichiers /etc/kmod-guard/allow.d/*.conf doivent appartenir à root et ne pas être modifiables par le groupe ou les autres. Les entrées sont séparées par des espaces; # commence un commentaire.

Entrée Correspond à
xfs le module xfs (- et _ sont équivalents)
nft_*, ip_set* un motif sur le nom du module (*, ?)
path:kernel/drivers/edac/ tous les modules dont le chemin sous /lib/modules/<kver>/ commence ainsi

Inutile de lister les dépendances : autoriser nfs garde aussi sunrpc, lockd, grace, etc.

  • 00-managed.conf est destiné à la gestion de configuration.
  • local.conf reçoit les ajouts faits sur l'hôte avec kmod-guard allow.
  • Tout autre fichier *.conf est lu également.

Liste par défaut

La liste par défaut pour serveurs autorise :

  • les pilotes matériels et de plateforme, par chemin : ACPI, stockage, cartes réseau, EDAC, cpufreq, hwmon, IPMI, virtio, Hyper-V, Xen, watchdogs, device-mapper;
  • les modules hors arbre (extra/, updates/, weak-updates/) : DKMS, CloudLinux kmod-lve, agents de sauvegarde;
  • les systèmes de fichiers courants;
  • les diagnostics de sockets de ss;
  • netfilter (iptables, nftables, ipset), que fail2ban, CSF, Imunify360 et Docker chargent à la première règle.

Restent bloqués, sauf si l'hôte les utilise déjà : les familles de sockets peu courantes, les ordonnanceurs, classificateurs et actions de contrôle du trafic, les périphériques réseau virtuels (vxlan, geneve, macsec…), AF_ALG, les systèmes de fichiers réseau et anciens (cifs, nfs, ceph, 9p, hfs…), les disciplines de ligne tty, RDMA, le son et la vidéo.

Exemples par rôle

Le dépôt fournit des exemples à copier dans /etc/kmod-guard/allow.d/ : Proxmox VE, Docker Swarm et WireGuard.

# Serveur WireGuard : les dépendances (curve25519, chacha20poly1305, udp_tunnel) sont gardées automatiquement
echo "wireguard" | sudo tee /etc/kmod-guard/allow.d/wireguard.conf
sudo kmod-guard generate

Commandes

kmod-guard generate [--dry-run] [--force] [--quiet] [--managed "<entrées>"] [--probe "<modules>"]
kmod-guard allow <module>...    autoriser sur cet hôte maintenant (écrit dans allow.d/local.conf)
kmod-guard disable              retirer la liste; reste désactivé jusqu'à `kmod-guard enable`
kmod-guard enable
kmod-guard status               état, autorisations locales, blocages récents
kmod-guard version

Deux options servent la gestion de configuration :

  • --managed prévisualise une nouvelle liste gérée sans l'écrire;
  • --probe répond à la question « lesquels de ces modules seraient bloqués ici? ».

Pour charger une seule fois un module bloqué, en tant que root :

sudo modprobe --ignore-install <module>

Vérifier l'exposition à une faille

Quand une faille touchant un module est divulguée, --probe indique si le serveur est protégé. Par exemple, pour les failles de 2026 :

sudo kmod-guard generate --dry-run --probe "algif_aead esp4 esp6 rxrpc act_pedit vsock vsock_loopback openvswitch pppoe cls_flower act_police sctp sctp_diag ah6 tun bridge kvm"
Faille CVE Modules à vérifier
Copy Fail CVE-2026-31431 algif_aead
Dirty Frag CVE-2026-43284, CVE-2026-43500 esp4 esp6 rxrpc
pedit COW CVE-2026-46331 act_pedit
VsockDrop CVE-2026-53365 vsock vsock_loopback
OVSwrap CVE-2026-64531 openvswitch
Zapscape CVE-2026-64561 kvm
PPPoEject CVE-2026-68121 pppoe
RtabRace CVE-2026-68138 cls_flower act_police
bridge-stp-uaf CVE-2026-72389 bridge
DiagSpill CVE-2026-74469 sctp sctp_diag
DirtyAH6 CVE-2026-80844 ah6
TUNderflow CVE-2026-81000 tun

La ligne probe_blocked= liste les modules qui ne peuvent pas être chargés. Un module absent de cette ligne est chargé ou autorisé sur ce serveur : c'est là qu'il faut appliquer le noyau corrigé en priorité.

Avec la liste par défaut, bridge et kvm restent autorisés, par choix. Ils font partie d'une chaîne de dépendances : bridge est requis par des modules netfilter autorisés (nft_meta_bridge, nft_reject_bridge, nf_conntrack_bridge), et kvm est gardé avec les modules du processeur (path:kernel/arch/x86/). Les bloquer par défaut risquerait de briser un pare-feu ou un hyperviseur. Sur un serveur qui n'en a pas besoin, resserrez la liste d'autorisation.

Journaux

$ journalctl -t kmod-guard
kmod-guard: blocked module=sctp trigger=explicit parent=bash[4121] uid=0 loginuid=1000 cmd=-bash
kmod-guard: blocked module=tipc trigger=autoload parent=kthreadd[2] uid=0 loginuid=unset cmd=

La valeur de trigger indique l'origine :

  • explicit : un processus a lancé modprobe;
  • udev : un périphérique correspondait;
  • autoload : le noyau a demandé le module lui-même, par exemple via socket(AF_TIPC, …). La demande passe par un fil du noyau, donc le processus à l'origine ne peut pas être identifié.

Le paramètre BLOCK_EXIT dans /etc/kmod-guard/kmod-guard.conf définit ce que retourne un chargement bloqué :

  • 0 (par défaut) : modprobe réussit sans rien charger, pour qu'un service qui lance modprobe foo dans ExecStartPre continue de démarrer;
  • 1 : le chargement échoue explicitement.

Sécurité de l'outil

  • Un module chargé n'est jamais bloqué. generate refuse d'écrire une liste qui en bloquerait un (code 70) ou une liste vide.
  • Le premier passage attend FIRST_RUN_MIN_UPTIME (1800 s par défaut).
  • Les dépendances sont résolues pour chaque noyau installé : un nouveau noyau dont les modules dépendent de quelque chose de nouveau l'obtient.
  • Les crochets initramfs retirent la liste des images de démarrage, pour qu'un nouveau noyau puisse toujours charger les pilotes du disque racine.
  • Les écritures sont atomiques et un fichier inchangé n'est pas réécrit.

Codes de sortie : 64 usage, 65 entrée d'autorisation invalide, 66 modules.dep ou /proc/modules manquant, 70 liste refusée, 77 fichier d'autorisation avec propriétaire ou permissions non sécuritaires.

Limites

kmod-guard n'est pas infaillible : c'est une couche de défense de plus, pas une garantie.

  • Certains modules restent autorisés par défaut parce qu'ils font partie d'une chaîne de dépendances (bridge, kvm). Une chaîne d'attaque peut passer par eux, ou par un module que le serveur utilise réellement.
  • Root peut toujours charger n'importe quel module avec insmod ou modprobe --ignore-install. kmod-guard limite ce qu'un utilisateur sans privilèges peut faire entrer dans le noyau; ce n'est pas une frontière contre root (voir kernel.modules_disabled pour cela).
  • Le code compilé directement dans le noyau (=y) n'est pas touché.
  • Autoriser netfilter et le contrôle du trafic garde ce que les espaces de noms utilisateur peuvent atteindre à travers eux. Restreindre ces espaces de noms (kernel.unprivileged_userns_clone=0, user.max_user_namespaces ou AppArmor sur Ubuntu 24.04) est complémentaire.
  • kmod-guard ne remplace pas les mises à jour du noyau.

Désactiver ou désinstaller

# Désactivation d'urgence : retire la liste jusqu'à `kmod-guard enable`
sudo kmod-guard disable

# Désinstallation (conserve /etc/kmod-guard et /var/lib/kmod-guard)
sudo make uninstall

Code source

Le code est disponible sur GitHub sous licence MIT : github.com/webo3/kmod-guard. L'idée vient de modulejail de Jasper Nuyens; kmod-guard est une implémentation distincte qui ajoute la résolution des dépendances, la mémoire des modules déjà vus et les autorisations par motif et par chemin.

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.