psf-linux-kernel-module-block(8)

Script: /opt/psf-security-patches/linux-kernel/linux-kernel-module-block.sh. Tool page: Linux kernel. Source. With the package installed: man psf-linux-kernel-module-block.

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/.lock

The 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.

The PrivacySafe Ecosystem

Shop at Ivy Cyber

Ivy Cyber offers PrivacySafe products and services in the USA and has partnerships with 3NSoft in Canada and Kuip Limited in the European Union. Enterprise services and consulting are available at ivycyber.com

PrivacySafe Foundation is a 501(c)(3) nonprofit public charity that supports the development of the PrivacySafe applications, along with the components they rely upon: 3NWeb protocols, filesystem, documentation, and reference implementations.

PrivacySafe Foundation

Donations to PrivacySafe Foundation support education, research, documentation, and public code. Purchases from Ivy Cyber support PrivacySafe products, services, hosting, and technical support. Together, we're building a better web.