Fun with UEFI
As a matter of fact, the title of this post is not meant in a sarcastic fashion. If you’ve come here thinking this is a rant about (U)EFI, I’ve got to disappoint you. :)
Anyways, since my SSD recently died and my backups were, ahem, lackluster, I had to set up my system from scratch. Since I didn’t really like the previous setup (LVM on LUKS) anyways, I figured I might as well try root on ZFS again. And if I’m at it, boot the whole thing with UEFI.
Now, I’ve heard some people curse UEFI like it’s the second coming of Bill Gates, and that it’s a royal pain in the ass to get working, etc. As I’m currently writing this from my shiny, new system booting from UEFI, you might guess that I can’t confirm this notion – though your mileage might vary.
Let’s get started, by stating the initial goal of the install:
- a shiny new Gentoo GNU/Linux
- booting entirely off ZFS
- from within an encrypted LUKS partition
- without a bootloader
- and nothing besides the kernel outside of the crypted partition
For the most part, I’ve followed the UEFI Quick Install Guide and the excellent Gentoo Handbook, with a bit of duck-fu on the side. This worked pretty smoothly, and I had no noteworthy problems with getting the entire thing to work.
Now, the interesting part, and the question that most of you will probably have had while reading the list of goals:
“How in the name of Eris are you supposed to boot an encrypted system running off ZFS without a bootloader or an initram?”
How it works
Enter two (more ore less) little-known Linux kernel configuration options: CONFIG_INITRAMFS_SOURCE and CONFIG_CMDLINE. What do they do? Let’s start with the latter: CONFIG_CMDLINE specifies a built-in kernel command line for Linux. Normally, you’d pass options to the kernel from the bootloader, but you can also compile a fixed default one into the kernel. Here is mine (stripped of a few uninteresting things):
CONFIG_CMDLINE="crypt_root=UUID=blahblah real_root=ZFS=KOS-MOS/ROOT/gentoo dozfs=force ro"
The options you see here are used by an initram generated with Gentoo’s genkernel utility, which brings us directly to the other option, CONFIG_INITRAMFS_SOURCE. This option takes a path to a cpio-compressed initram, and builds it directly into the kernel – and that is pretty much the entire magic behind this setup.
This setup has a few cool side effects, but the most important one is that there is only a single attack vector outside of the encrypted partition (well, two if you count the UEFI implementation). I’ve not tried this yet, but it should be possible to sign the kernel and activate Secure Boot, which would enable a completely trusted boot chain. I’m gonna fuck around with kernel signing a bit this week and maybe post a follow-up.
I’m not gonna lie, this setup has its downsides, too. First of all, it’s a pain in the ass to have to recompile (parts of) the kernel if you need to change the boot options. The same goes for changing something in the initram (though I only have to do this very rarely). It’s severely inflexible.