Date: Mon, 29 Mar 2021 06:50:34 +0000 From: bugzilla-noreply@freebsd.org To: bugs@FreeBSD.org Subject: [Bug 254637] [PATCH] Read kern.geom.eli.passphrase from UEFI variable for unattended boot without passphrase on disk Message-ID: <bug-254637-227@https.bugs.freebsd.org/bugzilla/>
next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D254637 Bug ID: 254637 Summary: [PATCH] Read kern.geom.eli.passphrase from UEFI variable for unattended boot without passphrase on disk Product: Base System Version: 12.2-RELEASE Hardware: Any OS: Any Status: New Severity: Affects Many People Priority: --- Component: kern Assignee: bugs@FreeBSD.org Reporter: kgeorge@tcpsoft.com Created attachment 223677 --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=3D223677&action= =3Dedit Patch to loader.efi to read kern.geom.eli.passphrase from UEFI environment TL;DR this patch reads kern.geom.eli.passphrase from a namespaced UEFI "environment variable" (NVRAM firmware variable), setting it in the boot environment for unattended boot of encrypted boot disks, without storing anything on-disk in the clear. GELI is used in FreeBSD to encrypt disks / partitions. When doing encrypti= on of the boot disk, the options to decrypt the boot disk at boot time are eit= her enter a passphrase, or (if applicable) keep an unencrypted /boot partition = on the disk with keys. However, in addition to not being a great idea (consid= er the threat model of having to RMA a drive, for example), the latter option = does not work with UEFI: the UEFI loader.efi [0] stage probes devices and when it probes a GELI partition, it prompts for a passphrase. So storing on disk in /boot is not an option with UEFI (and not really great anyway), and, at lea= st on ZFS root, /boot is part of the zpool and thus encrypted by GELI regardle= ss.=20 While the /boot option does work with legacy BIOS in some configurations, t= his is going away on modern systems. The FreeBSD boot system already looks for the variable kern.geom.eli.passph= rase in the boot runtime environment and, when present, this passphrase is used before prompting the user when it encounters a GELI-encrypted partition. S= o if there was some way to get kern.geom.eli.passphrase populated it would solve this problem ... UEFI has the ability to store arbitrary, namespaced variables in system NVR= AM.=20 These are stored separate from any boot media (like on the motherboard). T= his is good for at least two reasons: 1) we can read them early in the boot process, separate from any disk block and 2) because they're separate from = the disks, the keys are never written in the clear to disk. FreeBSD already ha= s a (mostly unused, as far as I can tell) UEFI variable namespace (cfee69ad-a0de-47a9-93a8-f63106f8ae99). We can store kern.geom.eli.passphr= ase there and read it into the boot environment _before_ disks are probed, maki= ng the rest of the boot infrastructure try it before prompting. The attached patch does just that. kern.geom.eli.passphrase can be written and read by userspace tool efivar: # write % cat passphrase | head -1 | tr -d $'\n' | doas efivar --name cfee69ad-a0de-47a9-93a8-f63106f8ae99-kern.geom.eli.passphrase -w # read % doas efivar -n cfee69ad-a0de-47a9-93a8-f63106f8ae99-kern.geom.eli.passphr= ase cfee69ad-a0de-47a9-93a8-f63106f8ae99-kern.geom.eli.passphrase 0000: 74 65 73 74 31 32 33 34 ^^^^^^^^^^^^^^^^^^^^^^^ test1234 efivar requires root to read/write. The patch, which is fairly simple (but took a while to figure out exactly where/how to patch), is inline and attached: diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index a5213a51d88b..ecce7a2e4bba 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -869,6 +869,8 @@ main(int argc, CHAR16 *argv[]) char boot_info[4096]; char buf[32]; bool uefi_boot_mgr; + char geom_eli_passphrase[256]; + UINTN geom_eli_bufsz; archsw.arch_autoload =3D efi_autoload; archsw.arch_getdev =3D efi_getdev; @@ -902,6 +904,22 @@ main(int argc, CHAR16 *argv[]) */ bcache_init(32768, 512); + /* + * Read kern.geom.eli.passphrase from the EFI environment under= the + * FreeBSD EFI GUID namespace (efi_freebsd_getenv). Read before scanning + * block IO media so that it's available when probing. + */ + geom_eli_bufsz =3D sizeof(geom_eli_passphrase); + bzero(geom_eli_passphrase, geom_eli_bufsz); + rv =3D efi_freebsd_getenv("kern.geom.eli.passphrase", geom_eli_passphrase, + &geom_eli_bufsz); + if (rv =3D=3D EFI_SUCCESS) { + printf("kern.geom.eli.phassphrase read from EFI env\n"); + env_setenv("kern.geom.eli.passphrase", EV_VOLATILE, + &geom_eli_passphrase, env_noset, env_nounset); + bzero(geom_eli_passphrase, geom_eli_bufsz); + } + /* * Scan the BLOCK IO MEDIA handles then * march through the device switch probing for things. To build: % cd /usr/src % patch -p1 < /path/to/patch.patch % cd /usr/src/stand/efi/loader % make % make install # changes /boot/loader.efi To install: % mount -t msdosfs /dev/gpt/efiboot0 /mnt/efi % cp /boot/loader.efi /mnt/efi/efi/boot/BOOTx64.efi To test: On any UEFI + GELI boot system, set the passphrase like above, and rebo= ot.=20 Your system should boot without prompting (assuming your passphrase is corr= ect, of course). I've tested this / I'm using this on my own machine: 12.2-RELEASE amd64, wi= th UEFI + GELI + zfsboot. Patch is made against 12.2 branch from the git mirr= or. [0] loader.efi is the first and last stage loader now, according to http://freebsd.1045724.x6.nabble.com/UEFI-loader-efi-and-boot-config-td6308= 485.html. boot1.efi, which used to be the first stage, is being phased out. --=20 You are receiving this mail because: You are the assignee for the bug.=
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-254637-227>