Build the lockdown LSM into the FOS kernel, without activating it - #131
Build the lockdown LSM into the FOS kernel, without activating it#131darksidemilk wants to merge 1 commit into
Conversation
A signed kernel that does not enforce lockdown is a Secure Boot bypass: anyone can boot it on a machine that trusts the signer and then reach the kernel through /dev/mem, iopl() or kexec_load(). shim-review asks about this directly, and it is the largest gap between FOS today and a kernel anyone would sign for general use. CONFIG_SECURITY was not even set, so the lockdown LSM could not be selected at all. This enables it and the platform keyring machinery across all three architectures -- LOAD_UEFI_KEYS being the one that imports the firmware's db and MokList, without which the kernel cannot see the key the shim just validated against. CONFIG_LSM is set explicitly because an LSM absent from the ordered list never initialises, and oldconfig's default string names LSMs this kernel does not build. CONFIG_KEXEC goes away: lockdown blocks kexec_load() unconditionally and FOS never used it. Lockdown is built in but left inactive (FORCE_NONE), so nothing changes for existing users. FORCE_INTEGRITY would have activated it in one line and is the wrong default -- it locks down every boot, including the overwhelming majority that never enable Secure Boot, and lockdown blocks the /dev/mem fallback that hardware inventory can still depend on. Distributions all carry a patch that activates lockdown only when the firmware reports Secure Boot on. That patch is NOT included here, and 0009 records why in detail: both halves of it turn out to be downstream only in 6.18 -- security_lock_kernel_down() is absent from mainline, as is efi_enabled(EFI_SECURE_BOOT) -- so it is a multi-file arch-specific patch. build.sh applies patch/kernel/linux.patch with `patch -p1` and exits on failure, so shipping one that has never been compiled would break every build and take the Intel VMD patch down with it. Because oldconfig silently drops symbols whose dependencies are unmet, a config can look right in git and still produce a kernel with no lockdown in it. tests/checks/secureboot-config.sh asserts the symbols are present, and with -b re-checks the .config Kconfig actually produced after a build. Not built or booted -- no kernel was compiled for this change. Build all three arches and confirm the Realtek NICs and Intel VMD NVMe still work before merging; those are the whole reason FOS carries a custom kernel.
|
Verified this doesn't break Secure-Boot-disabled operation, per a question during review. Grepped the whole repo for The rest of the diff is dormant either way: this PR deliberately does not include the patch that would activate lockdown based on the firmware's Secure Boot state (see ADR 0009's "not yet done" section), so Still stands: none of this has been built or booted (see "Not verified" above). The grep rules out the specific kexec concern, but Testing this before mergeThis is the PR most worth testing — it explicitly wasn't built or booted while writing it. git clone https://github.com/FOGProject/fos.git /tmp/fos-hardening-test
cd /tmp/fos-hardening-test
git fetch origin claude/secure-boot-shim-fos-ssnjdp-hardening
git checkout claude/secure-boot-shim-fos-ssnjdp-hardening
./build.sh -nka x64 --install-depConfirm the hardening symbols survived
|
Independent of #130 — branched from
master, no shared commits, lands in either order. Kept separate because #130 is safe and immediately useful, while this changes how every FOS kernel is built and deserves its own review and its own bisect point.Why
A signed kernel that does not enforce lockdown is a Secure Boot bypass: anyone can boot it on a machine that trusts the signer and then reach the kernel through
/dev/mem,iopl()orkexec_load().rhboot/shim-reviewasks about this directly:It is the largest gap between FOS today and a kernel anyone would sign for general use.
One thing makes this easier than usual: FOS has no modules.
# CONFIG_MODULES is not set, 1829=yand zero=m, and the out-of-tree Realtek drivers are built in-tree byaddKernelPackages()rather than as external modules. That answers shim-review's other recurring question — ephemeral per-build module-signing keys — with "we build no modules". Nothing to do there.What changed
CONFIG_SECURITYwas not set at all, so the lockdown LSM could not even be selected. Enabled across all three architectures, along with the platform keyring machinery —LOAD_UEFI_KEYSbeing the one that imports the firmware'sdbandMokList, without which the kernel cannot see the key the shim just validated against.CONFIG_LSMis set explicitly because an LSM absent from the ordered list never initialises, andoldconfig's default string names LSMs this kernel does not build.CONFIG_KEXECgoes away — lockdown blockskexec_load()unconditionally and FOS never used it.Lockdown is built in but left inactive (
FORCE_NONE), so nothing changes for existing users.FORCE_INTEGRITYwould have activated it in one line and is the wrong default: it locks down every boot, including the overwhelming majority that never enable Secure Boot, and lockdown blocks the/dev/memfallback that hardware inventory can still depend on.What is deliberately missing
Distributions all carry a patch that activates lockdown only when the firmware reports Secure Boot on. That patch is not here, and ADR 0009 records why in detail. Both halves of it turn out to be downstream-only in 6.18:
security_lock_kernel_down()— the function the Fedora/Ubuntu patches call — is not in mainline.include/linux/security.hexports onlysecurity_locked_down(), the query.efi_enabled(EFI_SECURE_BOOT)is also not in mainline. Upstream x86 keeps the state inboot_params.secure_bootand, insetup_arch(), only prints it.So it is a multi-file, arch-specific patch.
build.shappliespatch/kernel/linux.patchwithpatch -p1and exits non-zero on failure, so shipping one that has never been compiled would break every build and take the Intel VMD patch down with it. The ADR records the exact hook point found insetup.cand a smaller single-file alternative insecurity/lockdown/lockdown.c, so whoever picks it up does not repeat the search.The ADR also flags the question worth settling first: FOS boots as
bzImage+ a network-supplied command line + an unsigned ext2init.xz. A reviewer will push hard on that, and if FOG cannot move to a UKI, a shim application probably is not winnable — in which case the lockdown patch buys nothing on its own.Verified
make oldconfigsilently drops symbols whose dependencies are unmet, so a config can look right in git and still produce a kernel with no lockdown in it.tests/checks/secureboot-config.shasserts the symbols are present across all three configs, and with-bre-checks the.configKconfig actually produced after a build. It passes, and it was negative-tested — flippingCONFIG_SECURITY_LOCKDOWN_LSMoff makes it fail. Run it with-bafter your first build.Existing harnesses re-run:
wipe.sh,sector-size.sh,lvm.shand the golden fixture all pass.fill-engine.shfails, but it fails identically on unmodifiedmaster—procsfdisk.awkuses gawk syntax the test host's awk rejects. Pre-existing, untouched.Not verified
Warning
No kernel was compiled for this change. Before merging: build all three architectures, boot with Secure Boot off and image a machine end to end, and confirm the Realtek NICs and Intel VMD NVMe still work. Those two are the entire reason FOS carries a custom kernel, and
CONFIG_SECURITY/keyring churn is exactly the kind of change that could disturb them.🤖 Generated with Claude Code
https://claude.ai/code/session_01HZ2jZ7qgen6pXrbtmxShaw
Generated by Claude Code