Lion Cipher Lab
Sign your own kernel modules and enforce signature verification with kernel lockdown
- Cyber / Security Engineer
- Advanced
- ~90 min
- Free · no account required
Why it matters
The kernel is the most privileged code on the machine: it is ring 0, it mediates every process, every file, every packet, and it can see and rewrite anything. A loadable kernel module (a `.ko` file) runs at exactly that privilege — and by default, on a stock Linux box, ANY process with root can load ANY module. Sit with what that means: the moment an attacker has root, they can drop a kernel module that hides their processes, hooks the system-call table, disables your logging, and survives reboots — a kernel ROOTKIT — and the kernel will happily load it, because the kernel's default policy is…
What you'll learn
- the baseline threat in your bones: by default ANY root can load ANY kernel module, so on a stock machine 'got root' and 'can run arbitrary code in ring 0' are the same sentence — and a kernel rootkit is usually just a .ko
- building a trivial out-of-tree (built OUTSIDE the kernel source tree, against the running kernel's headers) hello-world module with a tiny obj-m Makefile, and loading it with insmod while reading dmesg
- generating an X.509 module-signing key pair (a public-key certificate + its private key) with openssl and the kernel's x509.genkey config, and signing the .ko against a SHA-256 hash with scripts/sign-file
- the difference between a module being SIGNED and a module being TRUSTED — a valid signature from a key the kernel does not trust is still rejected, and why that distinction is the whole point of a code-integrity control
- turning on enforcement (module.sig_enforce=1 on the kernel command line / CONFIG_MODULE_SIG_FORCE) and trusting your key via MOK (Machine Owner Key) enrollment under Secure Boot
- understanding the kernel lockdown LSM and its integrity vs confidentiality modes, and how lockdown ties module-loading integrity to a Secure Boot chain that even root cannot quietly disable
- PROVING the control by measurement: an unsigned module, an untrusted-signed module, and a byte-TAMPERED signed module are all rejected with 'Key was rejected by service' (EKEYREJECTED), while the correctly-signed, trusted module loads
- the named failure modes: forgetting to trust the key (even your own signed module is rejected), sig_enforce with no trusted keys bricking module loading, lockdown being meaningless without Secure Boot, a leaked signing key defeating the whole control, and version/kernel mismatch with modprobe --force
- the honest judgment: signature enforcement + lockdown is a defense-in-depth layer that RAISES the bar from 'any root loads any code into the kernel' to 'only you/vendor-signed code runs in ring 0' — but it depends on Secure Boot and key custody and is not an absolute
Steps in this lab
- First, the danger and the throwaway rule
- Build a hello-world kernel module and watch ANY root load it
- Generate an X.509 module-signing key pair
- Sign the module with the kernel's scripts/sign-file
- Turn on enforcement — and watch even your SIGNED module get rejected
- Trust your key with MOK enrollment, and understand lockdown
- Prove the control: unsigned, untrusted, and TAMPERED are all rejected
- The named failure modes, said plainly
- Judgment: what this buys you, and what it does not
- The way a pro does it — and what you actually built