Refuse Secure Boot enrolment on 32-bit UEFI (GH-140) - #142
Merged
Conversation
The enrolment task had no architecture check at all. On an ia32 client that meant one of two wrong outcomes. Outside Setup Mode it staged a MOK request, printed a one-time password and "a blue MOK Manager screen appears on the next boot", and reported Task Complete. Nothing will ever read that MokNew: MokList is a shim variable, and no Microsoft-signed 32-bit shim exists for such a machine to boot. Same false-success class as GH-136. In Setup Mode it was worse than useless. The db write itself works -- nothing in it is architecture-specific -- which is exactly why "degrade to the db path" looked like the reasonable answer. But the write has no chain to make bootable: ipxe/shim publishes shimx64.efi and shimaa64.efi only, iPXE's ipxeboot.tar.gz ships x86_64-sb/ and arm64-sb/ only, and FOG serves ia32 clients an unsigned i386-efi/snponly.efi. Meanwhile Setup Mode is the only state where the task can run there at all, and path 1 finishes by writing the PK -- which is what leaves Setup Mode. So it took a machine FOG could image, made it enforceable, and left it with nothing signed to load. PK is not reversible from the OS; recovery is a firmware trip. sbPlatformBits() reads /sys/firmware/efi/fw_platform_size. That is firmware width, not CPU width, and the distinction matters: ia32 UEFI overwhelmingly runs on 64-bit CPUs, so uname -m would answer a different question and answer this one wrongly. An unreadable value reads as "unknown" and callers proceed -- refusing on it would break x86-64 clients to guard a case the kernel has made impossible since 4.14. The refusal sits in fog.enrollsb beside the nonefi/noefivars ones, before the certificate fetch and before the already-trusted short-circuit: no db contents make enrolment useful here, so no state exists in which continuing tells the admin anything more useful. The 0009 ADR said "path 1 would still work there", which was true of the write and wrong about the outcome. Corrected, along with the note that FOG signing its own i386-efi/ipxe.efi with the key already going into db would change the answer -- shim only exists to bridge to Microsoft's trust, and that bridge is redundant once FOG's key is in db. Four cases added to tests/checks/secureboot.sh, mutation-checked against pinning the output to 64, passing the raw value through, and dropping the readability guard. That last mutation initially passed: the wildcard yields "unknown" for a missing file either way, so the guard was only observable on stderr. Rather than claim coverage the test did not have, the redundant 2>/dev/null came off and a case now asserts the silence -- which is the behaviour that actually matters on a BIOS-booted client. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #140.
The enrolment task had no architecture check. On an ia32 client that produced one of two wrong outcomes.
Outside Setup Mode it staged a MOK request, printed a one-time password and "a blue MOK Manager screen appears on the next boot", and reported Task Complete. Nothing will ever read that
MokNew—MokListis a shim variable and no Microsoft-signed 32-bit shim exists for the machine to boot. Same false-success class as #136.In Setup Mode it was worse than useless, and this is the part that reversed the recommendation in #134:
shimx64.efix86_64-sb/snponly.efi,ipxe.efishimaa64.efiarm64-sb/snponly.efi,ipxe.efiThe
dbwrite works — nothing in it is architecture-specific — which is exactly why "degrade to the db path" looked reasonable. But it has no chain to make bootable; FOG serves ia32 clients an unsignedi386-efi/snponly.efi. And Setup Mode is the only state where the task can run there, because nothing is enforcing. Path 1 finishes by writing thePK, which is what leaves Setup Mode. So degrading takes a machine FOG can image today, makes it enforceable, and leaves it with nothing signed to load — irreversibly from the client's side.The change
sbPlatformBits()reads/sys/firmware/efi/fw_platform_size— firmware width, not CPU width. ia32 UEFI overwhelmingly runs on 64-bit CPUs, souname -manswers a different question.fog.enrollsbrefuses before the certificate fetch and before the already-trusted short-circuit. Nodbcontents make enrolment useful here.unknownand callers proceed — refusing on it would break x86-64 clients to guard a case the kernel has made impossible since 4.14.Tests
47 cases (was 43), mutation-checked against pinning the output to 64, passing the raw value through, and dropping the readability guard.
That third mutation initially passed — a missing file reaches
unknownthrough the wildcard either way, so the guard was only observable on stderr. Rather than claim coverage the test didn't have, the redundant2>/dev/nullcame off and a case now asserts the silence, which is the behaviour that matters on a BIOS-booted client. Given this ADR has now recorded three designs that passed their tests and were still wrong, that seemed worth doing properly.The refusal itself is in the entry point beside the existing
nonefi/noefivarsones, which the harness also cannot reach — it sources the library, notfog.enrollsb. Verified by lifting the guard verbatim out of the script and running it against 32 / 64 / absent.🤖 Generated with Claude Code