psf-linux-kernel-module-block(8)
Linux kernel module blocker: list, check, block, status, rollback (v1)
Generic. A curated list of modules behind recent kernel flaws, or any name you give it.
If this software is helpful, consider a donation to our 501c3 nonprofit:
https://privacysafe.foundation
Many kernel flaws sit in a module that almost nobody needs and that loads by itself the
moment an unprivileged process opens the right socket or a device appears. Stopping that
module from loading removes the attack surface until a patched kernel is running. This
script does it the way the kernel documents, with a file of its own in modprobe.d for each
module, a manifest, and a rollback, and it tells you when a block cannot work.
What a block is. A `blacklist NAME` line stops the alias-based autoload, and an
`install NAME /bin/false` line also stops an explicit `modprobe NAME`. Both are written to
/etc/modprobe.d/psf-block-NAME.conf. Names are normalized: a hyphen and an underscore are the
same thing to the kernel.
What a block cannot do, and what the script does about it:
built into the kernel no modprobe rule can block it. The script refuses, and prints the
switch the list knows for it (a sysctl, for MPTCP).
loaded now it stays loaded until it is unloaded or the host reboots. The script
refuses unless you pass --force, which writes the rule anyway, and
--unload tries `modprobe -r` afterwards (it fails if something uses
the module).
in the initramfs a module can load from the initramfs before modprobe.d is read. After
a block the script prints the command that rebuilds it for this
system; --initramfs runs it (update-initramfs on Debian, Ubuntu and
Trisquel; dracut with -I on the RPM family and SUSE, because dracut
reads /etc/modprobe.d only for a host-only image). It is off by default because a rebuild
is slow and can fail on a full /boot.
a module others need blocking a module also stops the modules that depend on it: modprobe runs
the install rule of the blocked dependency, which fails, so the
dependent cannot load either. Blocking only the dependent leaves the base
module loadable. The list names both for a CVE and --cve blocks both.
needed to boot or log in a short protected list (storage, the root filesystems, USB host and
input drivers, virtio, device mapper) is refused, even with --force.
Only --force --allow-protected overrides it.
The list. Three groups, labeled for what they are:
exploited modules behind flaws that this collection has a tool for (the CVE is shown)
historic modules behind older kernel local root or remote flaws that are well known
hardening modules that almost no system needs and that carry attack surface (CIS style:
rare filesystems and network protocols, DMA buses, USB storage). No CVE is
claimed for these. Blocking them is a policy choice.
Each row says what a block breaks. Add your own rows with --list-file. A row ending in "keep" marks a
module that detection depends on (mptcp_diag, which ss -M reads): --group and --cve skip it, and it is
blocked only when named and with --force, because blocking it hides what you are looking for.
Usage:
./linux-kernel-module-block.sh [list]
list [--group exploited|historic|hardening|all] [--present] [--list-file FILE]
the table, with the state of each module on this host: loaded, built in,
loadable or absent, and whether a block is in place. --present shows only
the modules this host has. Read-only.
check NAME... for any module: its state, what holds it, its aliases, how it autoloads,
and where it is blocked already. Exit 0 = every module named is absent or
blocked, 1 = at least one is present and can still load. Read-only.
block NAME... | --group G | --cve ID [--force] [--unload] [--initramfs]
[--even-if-absent] [--allow-protected] [--list-file FILE] [--dry-run]
(root) changes the host: writes the block files and a manifest.
--group blocks every module of a group, --cve every module that lists the
CVE. Built-in and loaded modules are skipped with the reason.
status what this script blocked, and whether each block is effective: the file is
still there and unchanged, and the module is not loaded. Exit 0 = all
effective, 1 = at least one is not. Read-only.
rollback [NAME...] [--force] [--initramfs] [--dry-run] (root) removes the block files
this script wrote (all, or the named ones). A file you edited since is
kept unless --force.
version print the script version.
Exit codes: 0 done, or nothing found; 1 something needs attention (check: a module is present and can
still load; status: a block is not effective; block or rollback: something was refused or failed, and
the rest was done); 2 usage error, or the run cannot go on (nothing was changed).
Env: STATE_DIR (default /var/lib/psf-security-patches/linux-kernel-module-block) and
MODPROBE_D (default /etc/modprobe.d)
KERNEL_RELEASE override uname -r
KERNEL_MODULES_FILE, KERNEL_BUILTIN_FILE override /proc/modules and
/lib/modules/<release>/modules.builtin
SYS_MODULE_DIR override /sys/module
MODPROBE_DIRS the directories searched for rules that already exist, besides MODPROBE_D
(default /etc/modprobe.d /usr/lib/modprobe.d /lib/modprobe.d /run/modprobe.d)
OS_RELEASE_FILE instead of /etc/os-release
PSF_LOCK_WAIT seconds a run that changes the host waits for another one that is already
changing it (default 30); the lock is STATE_DIR/.lockThe Security Patches software and this documentation are dedicated to the public domain under CC0 1.0 Universal. Other pages on privacysafe.app/docs are CC BY-SA 4.0 unless the page says otherwise.