enforce kernel module software signature verification [module signing] / disallow kernel module loading by default

We can restrict kernel modules to only be loaded if they’re signed by a valid key. This increases security by making it harder to load a malicious module. We can do this by adding module.sig_enforce=1 as a kernel parameter.

https://www.kernel.org/doc/html/v4.19/admin-guide/module-signing.html

We can also prevent kernel modules from being loaded or unloaded after boot by setting kernel.modules_disabled=1 with sysctl. I don’t really see a point in this though as module loading requires root and if an attacker has root already, there’s no point in attempting to load a module. Even if the attacker did need to load a module, they could just set kernel.modules_disabled=0 with sysctl as they have root anyway. For some reason, the lockdown patch sets this but I don’t see any real security advantage and only potential breakages.

2 Likes

madaidan via Whonix Forum:

We can restrict kernel modules to only be loaded if they’re signed by a valid key. This increases security by making it harder to load a malicious module. We can do this by adding module.sig_enforce=1 as a kernel parameter.

With the same logic (as you used later on in your post), can’t root just
undo that?

1 Like

This would help if the user accidentally loads a malicious module and didn’t know about it. This also requires a reboot to remove the kernel parameter so it’s harder for an attacker to do it.

The bad thing with this though is that it would prevent out-of-tree kernel modules from being loaded. Any module that isn’t part of the original kernel source code can’t be loaded. This includes things like the wireguard module.

1 Like

Leaving this open a bit for more comments if any.

1 Like

Please implement.

See also:

1 Like
1 Like

Thanks, merged!

1 Like

It turns out I was wrong and kernel.modules_disabled can’t actually be reset. It will give an “Invalid argument” error if you try to set it to 0 after setting it to 1.

I found this guide (from the guys who made Lynis) and they seem to believe this increases security although their only actual justification was it “can be useful to achieve maximum hardening of your Linux system”.

1 Like

Can this be applied to an already built kernel? Or is it part of the build process? I know it can work independent from secure boot.

1 Like

Yes, it can be changed at runtime with sysctl. Just run sysctl kernel.modules_disabled=1 as root or set it in a file in /etc/sysctl.d.

2 Likes

Fantastic. So we can just toggle it for the signed Debian kernels we already use :slight_smile:

2 Likes

kernel.modules_disabled=1 is starting to sound like more of a good idea.

Kees Cook (a security engineer at Google), seems to think this is a good thing.

https://outflux.net/blog/archives/2009/07/31/blocking-module-loading/

The intent is for this to allow paranoid server admins (or other people not expecting to hot-plug new hardware or kernel services) the ability to block module loading without compiling a monolithic kernel.

Combined with the removal of /dev/kmem and the hardening of /dev/mem, this closes another kernel rootkit door. It’s not a cure-all, but it’s another layer.

https://outflux.net/slides/2013/drupal/tunables.pdf

kernel.modules_disabled=1

● Trivial jump from root user into kernel code

– Remember the iframe injector?

It is recommended on the Tor wiki although for a different reason so not really applicable.

Once access to the ptrace system call is removed, you need to disable module loading to prevent it from being restored. On Linux, this is accomplished via ‘sysctl kernel.modules_disabled=1’. You should perform this operation as early in the boot process as possible.

Also see

If we do choose to implement this, how to revert it should be documented as this can break a lot of things.

2 Likes

ClipOS sets this too. Kernel — CLIP OS 5.0.0_beta3 documentation

kernel.modules_disabled = 1

Disable module loading once systemd has loaded the ones required for the running machine according to a profile (i.e., a predefined and hardware-specific list of modules).

GrapheneOS does something similar. Build | GrapheneOS

As part of the hardening in GrapheneOS, it uses fully monolithic kernel builds with dynamic kernel modules disabled. This improves the effectiveness of mitigations like Control Flow Integrity benefiting from whole program analysis. It also reduces attack surface and complexity somewhat including making the build system simpler.

1 Like

IIRC this is permanent once set?

2 Likes

No. As far as I know, any /etc/sysctl.d drop-in or /etc/default/grub.d boot parameter drop-in can be disabled by:

  • deleting that configuration file (this will always work)
  • dropping a lexical higher configuration file snippet that will undo the previous configuration file snippet (this will work likely, should work, but needs testing)
2 Likes

Only for the current session. The kernel has no recollection of past sysctl settings so they’re all reset at shutdown. Setting it in /etc/sysctl.d makes it persistent but the user can just edit/delete that file and reboot.

2 Likes

Setting kernel.modules_disabled=1 in /etc/sysctl.d broke a lot of things. whonix-firewall, onion-grater, kloak and some others all failed to start and the screen hanged.

We can set it similar to the way we set kernel.panic_on_oops=1 so it will be set after those have already started.

2 Likes

That’s a good idea. Set a timeout of 30 seconds or something so newly plugged in hardware has a chance to load its modules before system use.

2 Likes

Time based will be prone for race conditions. Something (not) working on fast vs slower computers / under light/heavy (host) load. systemd allows to define exactly when is a good time to dispatch this the question is just what is the right time to do this.

1 Like

Documentation for /proc/sys/kernel/ — The Linux Kernel documentation says the same

modules_disabled:

A toggle value indicating if modules are allowed to be loaded in an otherwise modular kernel. This toggle defaults to off (0), but can be set true (1). Once true, modules can be neither loaded nor unloaded, and the toggle cannot be set back to false. Generally used with the “kexec_load_disabled” toggle.

Btw we have kexec disabled already as per:

https://github.com/Whonix/security-misc/blob/master/etc/sysctl.d/kexec.conf

2 Likes