14 Dec 2017

FreeBSD: Full-Disk Encryption + UEFI

How to install FreeBSD using a GELI-encrypted UFS root partition on UEFI.

After the almost comical stream of OS X security bugs recently, I dug up my old ThinkPad T530 and installed FreeBSD as my primary OS. Since a laptop is portable and easily stolen, full-disk encryption is a must. There are plenty of resources online for setting up an encrypted ZFS root partition on FreeBSD, but I still prefer UFS on desktop setups. Don't get me wrong—ZFS is my top choice for any kind of RAID situation—but I've always found it a bit overkill (and RAM intensive) for a single-disk OS partition. And I definitely wanted UEFI for that native resolution console at boot time. :-)

There were hardly any guides online for installing FreeBSD to a GELI-encrypted UFS partition, and there was even less information about how to get such a setup working with UEFI. However, I eventually figured it out, so here's a quick how-to in case another discerning daemon finds his way here.

Configuring Your BIOS

I'm not sure if "BIOS" is the right word anymore, but you know what I mean. Reboot your computer and spam the F2 or Delete key or whatever magic incantation you need in order to get to your BIOS settings. You'll definitely need to disable Secure Boot, since it doesn't work yet (and why would you want it, anyway?). On my ThinkPad, I also had to disable all the compatibility boot options. Most of these options were labeled "CSM".

While you're in the BIOS, you might want to go ahead and disable the TPM if you have one—I've seen many reports that it breaks resuming from suspend in FreeBSD.

Partitioning the Disk

At this point, I'm assuming that you've successfully booted the FreeBSD installation media via UEFI. If the installer won't boot in pure UEFI mode, then you're probably out of luck—but the GELI encryption section of this guide might still be helpful to you.

Once you get to the partitioning step in the FreeBSD installer, choose the Shell option to manually partition the disks. The first thing you'll need to do is figure out which block device corresponds to your hard drive. To show the current disk layout, just run:

gpart show

I'm going to assume your hard drive is called ada0. Let's blow away the current partition table and write a fresh GPT partitioning scheme.

gpart destroy -F ada0
gpart create -s gpt ada0

The first partition you'll need is an EFI System Partition. This is a small FAT-formatted partition from which your computer's firmware will boot the operating system. It just needs to be large enough to hold the FreeBSD UEFI bootloader—800 KB is plenty.

gpart add -t efi -l freebsd-efi -a 4k -s 800k ada0
newfs_msdos /dev/gpt/freebsd-efi

Your computer's UEFI firmware should look for a boot executable in a specific location on this partition. You'll need to mount the partition, create the folder hierarchy, and copy over the FreeBSD UEFI bootloader from the install media:

mount -t msdosfs /dev/gpt/freebsd-efi /mnt
mkdir -p /mnt/EFI/BOOT
cp /boot/boot1.efi /mnt/EFI/BOOT/BOOTX64.efi
echo BOOTx64.efi > /mnt/EFI/BOOT/STARTUP.NSH
umount /mnt

Next, you'll need a boot partition. Confusing, I know. The EFI partition you just created contains a small UEFI bootloader. However, this bootloader's only purpose is to look for a UFS (or ZFS) partition which contains the real FreeBSD bootloader, and then run it. The boot partition will also contain the kernel, boot configuration, and kernel modules.

This partition will have to remain unencrypted, since the bootloader needs to be able to find a kernel to execute. There are some guides online for storing your boot partition and kernel on an external USB stick to achieve a fully encrypted system, but I'm not that paranoid.

Anyway, create the boot partition. 1 GB is probably overkill for the FreeBSD kernel, but I've got plenty of disk space. If you have an SSD, be sure to pass the -t flag to newfs to enable TRIM support.

gpart add -t freebsd-ufs -l freebsd-boot -a 4k -s 1g ada0
newfs -t -U -L bootfs /dev/gpt/freebsd-boot

Finally, create a partition for your root filesystem. I don't bother with swap for a desktop machine, so I'll just use the entire remainder of the disk.

gpart add -t freebsd-ufs -l freebsd-root -a 4k ada0

Notice we didn't create a filesystem this time. That comes in the next section.

GELI Encryption

Now it's time to create your encrypted partition! FreeBSD's framework for disk encryption is called GELI. Basically, it's a layer in between the filesystem and the physical disk that manages encryption/decryption of the data blocks. Creating your GELI root partition is a one-liner:

geli init -b -e AES-XTS -l 256 -s 4096 /dev/gpt/freebsd-root

The -b flag is critical, as it allows the encrypted partition to be used as a root filesystem.

This will prompt you for an encryption passphrase. Use a good one! You will have to enter this passphrase every time you boot your computer (and if you forget it, you're SOL). Once that's done, issue the following command to unlock the drive (it will prompt you for the passphrase you just created):

geli attach /dev/gpt/freebsd-root

Now you can create the root UFS filesystem. Note the .eli extension on the block device this time:

newfs -t -U -L rootfs /dev/gpt/freebsd-root.eli

Mounting the Filesystems

To complete the partitioning step, the FreeBSD installer expects you to mount your root filesystem at /mnt:

mount /dev/gpt/freebsd-root.eli /mnt

However, there is one very important caveat regarding the boot partition. The bootloader expects everything to be under a folder called /boot on the boot partition itself. Therefore, for the FreeBSD installer to work, we'll need to mount the boot partition under a separate directory and create a symlink:

mkdir /mnt/bootfs
mount /dev/gpt/freebsd-boot /mnt/bootfs
cd /mnt
mkdir bootfs/boot
ln -s bootfs/boot

(Special thanks to ross at daemon-notes.com for that tidbit.)

Finally, you'll need to create an fstab and loader.conf file for your system to be bootable. At this stage in the installation, you can place these under /tmp/bsdinstall_* and the installer will copy them to the target filesystem appropriately.

/tmp/bsdinstall_etc/fstab
/dev/gpt/freebsd-root.eli / ufs rw 1 1 /dev/gpt/freebsd-boot /bootfs ufs rw 0 0

/tmp/bsdinstall_boot/loader.conf
geom_eli_load="YES" vfs.root.mountfrom="ufs:ada0p3.eli"

At this point, you're finished! Exit the shell to continue the FreeBSD installation.

Conclusion

Once the installer has finished, you may want to open a shell before you reboot, just to make sure your fstab and loader.conf files look correct. With any luck, your computer's UEFI firmware will be able to find your bootloader and launch the FreeBSD kernel.

When your system reboots, it will prompt you for your encryption passphrase during the boot process. The prompt is easy to miss during the text-scrolling frenzy, so if it seems hung, just type your passphrase and press enter.