Linux kernel module whitelisting
In the last weeks, several high severity vulnerabilities in the Linux kernel have been exposed (most notably Copy Fail and Dirty Frag), leading to local privilege escalations (LPE).
What they share is that they exploit kernel modules that are not totally obscure but definitely not loaded by default on every installation. So to reduce attack surface, it would be natural to only allow loading modules that are actually desired to be loaded.
I'm in no way the first person to have that idea. Fedora has a feature proposal dated 2010 to introduce whitelisting. But sadly, nobody ever did.
So what I did was write a small script that whitelists all modules currently
loaded and then aliases all others to /bin/true, effectively preventing them
from being loaded.
#!/bin/sh
set -eu
OUTDIR="${1:-/etc/modprobe.d}"
if [ "$#" -lt 2 ]; then
awk '{print $1}' /proc/modules | xargs -r -n1 "$0" "$OUTDIR"
cat > "$OUTDIR/whitelist.conf" <<-EOF
alias * blacklisted
install blacklisted /bin/true
EOF
exit 0
fi
MODULE="$2"
OUTFILE="$OUTDIR/whitelist-$MODULE.conf"
exec > "$OUTFILE"
echo "alias $MODULE $MODULE"
export MODULE
modinfo "$MODULE" | awk '$1 == "alias:" {printf "alias %s %s\n", $2, ENVIRON["MODULE"]}'
modinfo "$MODULE" | awk '$1 == "depends:" {print $2}' | tr -d '\n' | xargs -r -d, -n1 "$0" "$OUTDIR"
What the script does is that, for each loaded module, it adds a file
/etc/modprobe.d/whitelist-$MODULE.conf containing the lines alias $MODULE
$MODULE and alias $ALIAS $MODULE, and after that was done for all loaded
modules and their dependencies, it adds another file
/etc/modprobe.d/whitelist.conf containing the lines alias * blacklisted and
install blacklisted /bin/true.
There are several important aspects:
- Whitelisting has to be performed for the modules as well as all their
aliases. If you only whitelist
ext4but not its aliasfs-ext4, mounting ext4 filesystems will fail because the kernel tries to autoload the module by its alias. - Dependencies have to be whitelisted as well.
- Trying to load any non-whitelisted module will fail silently, without any
error message. This is due to the handling of aliases in modprobe: Since both
aliasdirectives match – the whitelistingalias modname modnameas well as the blacklistingalias * blacklisted– modprobe tries to load both modules. So if I had usedinstall blacklisted /bin/falseinstead, loading whitelisted modules would have exited with an error code as well. - Keeping this module whitelist up to date is tedious work. Especially for
distribution upgrades, removing the functionality altogether (with
rm /etc/modprobe.d/whitelist*.conf) and re-running it afterwards is probably best. But strange error messages might pop up in other places as well. You can later add an additional whitelist entry for$MODULEby calling the script with the parameters/etc/modprobe.d $MODULE.