Enable checks on notifier call chains
Requires the kernel to be built with CONFIG_DEBUG_NOTIFIERS=y, which validates notifier call chains at runtime.
Checked against the resolved running state (e.g. sshd -T, sysctl, systemctl show), catches drop-ins and Includes a file read would miss. Caveat: runtime ≠ persistence; a value correct now may not survive a reboot.
Pavois asserts the effective configuration, the live, resolved state, not a file. File-based scanners (OVAL/SCAP, Lynis) miss Includes, drop-ins and runtime defaults; this check sees what is actually applied.
A mapping is a cross-reference to where each standard places this requirement, anchored and cross-validated, not a claim of equivalence. A passing check is evidence toward these references, how to read it.
Why this rule matters
This provides validation of notifier chains, it checks whether the notifiers are from the kernel or a module that is still loaded prior to being invoked.
What Pavois checks
Pavois reads the effective kernel build flag from the running kernel: /boot/config-$(uname -r) (the config of the booted image) or /proc/config.gz when exposed. It keys on $(uname -r), so it inspects the kernel that is actually live, not a .config left over from a build tree or a different installed image. A file-based scan that just greps a fixed path could report a stale or unrelated config.
describe command("C=/boot/config-$(uname -r); if [ -r \"$C\" ]; then cat \"$C\"; elif zcat /proc/config.gz 2>/dev/null | head -1 | grep -q .; then zcat /proc/config.gz; else echo PAVOIS_NO_KERNEL_CONFIG; fi | grep -E '^(CONFIG_DEBUG_NOTIFIERS=|PAVOIS_NO_KERNEL_CONFIG)'") do
its('stdout') { should_not match(/PAVOIS_NO_KERNEL_CONFIG/) }
its('stdout') { should match(/^CONFIG_DEBUG_NOTIFIERS=y$/) }
endHow to verify it is applied
Run grep '^CONFIG_DEBUG_NOTIFIERS=' /boot/config-$(uname -r) (or zcat /proc/config.gz | grep '^CONFIG_DEBUG_NOTIFIERS='). Expected output: CONFIG_DEBUG_NOTIFIERS=y. Anything else (absent, or # CONFIG_DEBUG_NOTIFIERS is not set) is a failure.
Inspect & investigate
When the option is active and a malformed notifier is detected, the kernel logs a warning visible via dmesg | grep -i notifier or journalctl -k | grep -i notifier. The build flag itself does not produce logs; confirm it with zcat /proc/config.gz | grep NOTIFIERS.
Remediation
No automated remediation is shipped for this rule: a kernel build flag cannot be toggled by editing a file. It must be applied manually by installing a kernel compiled with CONFIG_DEBUG_NOTIFIERS=y (a hardened or custom kernel) and rebooting onto it.
Pavois applies this with its own harden engine, the plan below, not a shell script:
| resource | kernel_build |
|---|
pavois harden plan localwhere the target is local, a user@host SSH alias, or a container , Docs
Impact & precautions
Without CONFIG_DEBUG_NOTIFIERS, a notifier registered by a module that has been unloaded can leave a dangling function pointer in a notifier chain. When that chain is later fired, the kernel jumps into freed or reused memory, a use-after-free condition that can crash the system or be steered toward code execution. This is a build-time option: it can only be changed by installing a kernel image compiled with it, not at runtime. Precautions: the stock distribution kernels usually do not set this option; switching to a custom or hardened kernel changes ABI and module compatibility, so validate that out-of-tree drivers still load and test on a non-production host before rolling out. No reboot risk beyond a normal kernel swap.
Standards mapping
| Standard | Reference | Type | Version | Confidence |
|---|---|---|---|---|
| ANSSI BP-028 | R16 | direct | 2.0 | high |
Each reference is a cross-reference anchored in the upstream benchmark and cross-validated against the SCAP Security Guide and ansible-lockdown, not a claim of equivalence. Direct = a prescriptive, line-level requirement; supporting = an abstract control family (NIST) the check provides evidence toward. How to read a mapping.