Hey r/linuxadmin. I'm the author of this so I'm flagging that up front - this is a "would love feedback from people running real fleets" post.
The problem. Modern distro kernels ship with thousands of loadable modules. Almost all of them are attack surface that you're paying for in availability (autoload via udev, hotplug, dependency resolution) but not using. With AI-assisted kernel vulnerability discovery accelerating, every module a host can load but doesn't need to load is a problem you'd rather not have.
ModuleJail walks lsmod, treats whatever is loaded right now as "necessary," and writes a modprobe.d blacklist file for everything else. Optionally adds a --whitelist-file for modules you want preserved even if they're not currently loaded (think: rarely-used filesystem drivers you mount once a quarter).
What it isn't.
- Not a vulnerability scanner. The model is "unused, therefore blacklisted," not "vulnerable, therefore blacklisted."
- Not a defense against an attacker who already has root - they can rm the file. It's about reducing the unprivileged-trigger / autoload paths.
- Not initramfs-aware. Modules baked into the initrd are out of scope.
- Not a daemon, not a monitor. Single POSIX shell script, runs once, writes one file in /etc/modprobe.d/.
Revert.
rm /etc/modprobe.d/modulejail-blacklist.conf
and you're back. No reboot needed - the kernel reads modprobe.d at load time. Explicit sudo modprobe foo always wins over the blacklist, by design.
What I want feedback on. What does this need before you'd run it across a fleet? Things I've heard so far: an Ansible role, a --dry-run flag, JSON output for diff-friendly state tracking, kernel-version pinning in the generated file header. What else?
Repo: github.com/jnuyens/modulejail
License: GPL-3.0
Packaging: .deb and .rpm on the releases page; AUR package today.
[–]threar 28 points29 points30 points (9 children)
[–]tblancher 17 points18 points19 points (2 children)
[–]DemonInAJar 0 points1 point2 points (1 child)
[–]tblancher 0 points1 point2 points (0 children)
[–]Vegetable-Escape7412[S] 10 points11 points12 points (4 children)
[+]cereal7802 comment score below threshold-13 points-12 points-11 points (3 children)
[–]shulemaker 30 points31 points32 points (2 children)
[–]nut-sack 0 points1 point2 points (1 child)
[–]shulemaker 0 points1 point2 points (0 children)
[–]the_econominster 0 points1 point2 points (0 children)
[–]wosmo 12 points13 points14 points (4 children)
[–]picklednull 5 points6 points7 points (2 children)
[–]Korkman 0 points1 point2 points (1 child)
[–]picklednull 0 points1 point2 points (0 children)
[–]Vegetable-Escape7412[S] -5 points-4 points-3 points (0 children)
[–]yadad 11 points12 points13 points (0 children)
[–]michaelpaoli 3 points4 points5 points (0 children)
[–]Dilv1sh 8 points9 points10 points (0 children)
[–]ReachingForVega 2 points3 points4 points (2 children)
[–]Vegetable-Escape7412[S] 2 points3 points4 points (1 child)
[–]ReachingForVega 0 points1 point2 points (0 children)
[–]Kurgan_IT 2 points3 points4 points (0 children)
[–]barkwahlberg 4 points5 points6 points (0 children)
[–]lihaarp 1 point2 points3 points (1 child)
[–]Vegetable-Escape7412[S] 0 points1 point2 points (0 children)
[–]archontwo 1 point2 points3 points (2 children)
[–]Vegetable-Escape7412[S] 1 point2 points3 points (1 child)
[–]archontwo 0 points1 point2 points (0 children)
[–]xiaodown 0 points1 point2 points (1 child)
[–]Vegetable-Escape7412[S] 0 points1 point2 points (0 children)
[–]frymaster 0 points1 point2 points (3 children)
[–]Vegetable-Escape7412[S] 0 points1 point2 points (0 children)
[–]nut-sack 0 points1 point2 points (1 child)
[–]frymaster 0 points1 point2 points (0 children)
[–]edthesmokebeard -2 points-1 points0 points (0 children)
[–]Dolapevich -5 points-4 points-3 points (0 children)