You are viewing jwboyer

pointless pontifications of a back seat driver - Adventures in SecureBoot [entries|archive|friends|userinfo]
jwboyer

[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Adventures in SecureBoot [Aug. 9th, 2012|01:19 pm]
Previous Entry Share Next Entry
[Tags|]

Obligatory warning: This post is about Secure Boot. I will not discuss any of the larger political issues that surround this. If you wish to discuss those, I'm sure there are many forums out there for you to do so. End warning

So I have this problem. I work best when I actually do hands on stuff with something. I learn better, I retain more information, and I generally feel better about something if I can actually make it work. That might all sound like good stuff, but it tends to lead me to places that most don't want to go (see PowerPC, NOR flash, kernel programming), which is how I found myself enabling a machine to boot with UEFI Secure Boot enabled yesterday.

I have been trying to get a machine with UEFI firmware on it for quite some time, and recently one of the UEFI development platforms showed up at my door. The first thing I did was scratch install it with Fedora 17. Aside from having to use shiny rotating media because the machine really hates my USB key, that all went fine. So I had a decent machine booting via UEFI with grub-efi, the F17 3.5.0 kernel, and normal userspace. This is a testament to the work that others have done. It was boring that it just worked.

Not content to be bored, I decided that I was going to fully enable Secure Boot on this machine. For those of you that don't remember, that means there is a Platform Key (PK) and signing cert in DB both enrolled in the UEFI firmware. Then the SecureBoot UEFI variable is set to 1 and the firmware will refuse to load binaries that are not signed with said key (I am summarizing here).

The Fedora way of booting in this mode is to use something called shim, which will load a signed grub. The signed grub will then load a signed kernel. That kernel will then do various checks and boot into a locked down Secure Boot mode. Sounds simple, right? It actually is once you get your head around all the terminology and understand what's needed. So, off I went to accomplish this.

Fedora 17 installs on EFI machines with grub-efi. That was a temporary thing while the EFI work was being done in grub2. So Fedora 18 is going to use grub2-efi to boot EFI machines. Naturally, I needed to convert the box to use grub2-efi for booting first. A simple install of grub2-efi and grub2-tools and I had the binaries on the box. The next thing that was needed is to create an EFI Boot000X entry for it so I can use that to select grub2 as the bootloader. I had never used efibootmgr before, but after playing around with it for a bit, the invocation was simple enough:
efibootmgr -c --disk /dev/sda --part 1 --write-signature --label "Fedora (Grub 2)" --loader '\EFI\fedora\grubx64.efi'

That created a Boot0004 EFI variable that pointed to the grubx64.efi binary. After creating grub.cfg using grub2-mkconfig and putting it in /boot/efi/EFI/fedora/ I had what I needed to boot using grub2. There was a bit more manual configuration needed than I care for, but this stems from converting to grub2 after the fact instead of having anaconda setup the box during install. That is fixed in the current F18 tree.

Having that done, the next thing I needed was a key to use to sign things and enroll in UEFI. Fedora is using a tool written by Peter Jones called pesign. I was originally going to generate a cert to use with pesign, but Peter had already built a pesign package with test certs included. Those work fine for me, so I grabbed that. As I was off building a kernel to sign Peter realized that we should allow any user to sign things. That is actually fairly important since the Fedora build system does not build as root, but a buildtime created local user. A quick fix and Peter had a pesign that would work as non-root for signing. Bug fix #1.

Having certs and the pesign tool working, I wanted to build signed versions of shim, grub2-efi, and the kernel. Naturally, I started with the kernel. This turned out to be pretty trivial to do with a few simple changes to the Fedora kernel.spec file:

--- a/kernel.spec
+++ b/kernel.spec
@@ -551,7 +551,7 @@ BuildRequires: rpm-build >= 4.9.0-1, elfutils >= elfutils-0.
%endif

%if %{signmodules}
-BuildRequires: gnupg
+BuildRequires: gnupg pesign
%endif

Source0: ftp://ftp.kernel.org/pub/linux/kernel/v3.0/linux-%{kversion}.tar.xz
@@ -1600,6 +1600,11 @@ BuildKernel() {
if [ -f arch/$Arch/boot/zImage.stub ]; then
cp arch/$Arch/boot/zImage.stub $RPM_BUILD_ROOT/%{image_install_path}/zIma
fi
+ %if %{signmodules}
+ # Sign the image if we're using EFI
+ pesign -c "Red Hat Test Certificate" -s -i $KernelImage -o vmlinuz.signed
+ mv vmlinuz.signed $KernelImage
+ %endif
$CopyKernel $KernelImage \
$RPM_BUILD_ROOT/%{image_install_path}/$InstallName-$KernelVer
chmod 755 $RPM_BUILD_ROOT/%{image_install_path}/$InstallName-$KernelVer

After building this, I installed the kernel and rebooted and it booted fine. Good, that means a signed kernel doesn't cause issues in non-SecureBoot mode.

I went to sign grub2-efi, but Peter pointed me to a build in koji that was already signed similarly so I just grabbed that. Then I needed a signed shim. Except shim isn't in Fedora yet since it is still waiting on review. So I headed over to the shim review bug and grabbed the latest SRPM from there.

I hit a couple of small hiccups with shim. The first is that grub2-efi installs into /boot/efi/EFI/fedora/ while shim was setup to install into /boot/efi/EFI/redhat/. That was fixed easily enough, so a quick rebuild and I was set to test. Up to this point, I had been booting with an unsigned grub2 binary. I wanted to actually try booting with shim before I enabled Secure Boot to make sure things were working in general. After installing the package, I went to efibootmgr again:
efibootmgr -c --disk /dev/sda --part 1 --write-signature --label "Fedora (shim)" --loader '\EFI\fedora\shim.efi'

and off I went to test. Except it didn't work. It reported:

Unsupported image type
Failed to read header
Failed to load grub

Well, boo. That's not what I really wanted to happen. I found Matthew Garrett online and discussed this a bit. He and Peter worked out that shim was calculating the image size incorrectly and he came up with a patch rather quickly. Another rebuild and install and shim was loading grub2 which then booted the kernel. Bug fixes #2 and #3. At this point, I had a signed kernel and grubx64.efi installed. So I signed shim.efi with pesign similarly to everything else and rebooted into UEFI. Now it was time to enable Secure Boot in the firmware and see how things fared.

A quick digression first though. All of this signing was done with a test key. In actuality, that isn't how things will be set up for most machines. As discussed many times elsewhere, most machines shipping with Secure Boot enabled will come with a Microsoft key enrolled already. That means that shim.efi would need to be signed with that MS key if things were to install out-of-the-box and that is what the current F18 Feature proposes. The interactions of all the components are the same, with the only difference in being the setup. The Feature aims to let users boot without doing anything I'm actually discussing here. What I have spent time doing is essentially the secondary option a user can take, which is to enroll their own set of keys and establish their own chain of trust on their machine. I just wanted to clarify that.

So sitting in UEFI, I needed to enroll the test keys into the Platform Key (PK) and DB EFI variables. The firmware provides options to do this by hand. One just needs to have the keys accessible to the firmware on a USB key or CD or similar and use those options to enroll them. Then you enable the SecureBoot option and reset the machine. Matthew wrote a simple EFI binary to do all of this for me, so I used that instead.

When the machine rebooted, I started shim and was presented with:

Starting file via StartImage
Welcome to GRUB!

error: file `/EFI/fedora/locale/en.mo.gz' not found.
Binary is whitelisted

Success! UEFI booted the signed shim.efi, shim loaded the signed grubx64.efi. Then I let grub boot the signed kernel, which also worked. I was quite excited until I ran
 dmesg | grep Secure
and got exactly nothing back. I was looking for a message that said 'Secure boot enabled'. I wrote a patch a while ago to force SB mode on in the kernel if you pass a kernel parameter on the command line. I did that because I didn't have a UEFI box and I wanted to test that we were locking stuff down properly. So I know that message should be popping up on an actual UEFI box if SB is enabled and yet it wasn't.

I poked around in /sys/firmware/efi and the variables were all showing that SB should be enabled. That meant the code that runs as part of the EFI stub to check those variables was failing for some reason. This was a bit baffling. After a bit of debugging, it turns out the call to get the SecureBoot variable was returning EFI_NOT_FOUND which was even more baffling. I went to bed thoroughly perplexed.

This morning I woke up and remembered Matthew had sent a patch to LKML a bit ago that passed some specific CFLAGS to the EFI boot stub. I looked at the rawhide tree and realized that patch was missing. Adding it in quickly and rebuilding and there was my Secure boot enabled message I was looking for:

[jwboyer@efi ~]$ dmesg | grep Secure
[ 0.000000] Secure boot enabled
[jwboyer@efi ~]$ uname -a
Linux efi 3.6.0-0.rc1.git3.2.fc18.x86_64 #1 SMP Thu Aug 9 08:39:32 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux
[jwboyer@efi ~]$

Turns out that without the -fshort-wchar flag being passed, L"SecureBoot" winds up being UCS-4 and not UCS-2 which is what UEFI expects. EFI_NOT_FOUND indeed. Bug fix #4. I count myself lucky that I didn't have to actually debug that out.

So here I sit with a UEFI machine fully booted into Secure Boot mode. I learned quite a bit along the way and I'm better off for it. Hopefully the bugs I found help the final product for F18 and save some users and testers pain along the way. There's still some work to do, but now I'm in a much better position to actually do it.

For those curious, these are the builds of the packages I'm currently running:

pesign: http://koji.fedoraproject.org/koji/buildinfo?buildID=346700
shim: No Fedora build yet, but I put my build here: http://jwboyer.fedorapeople.org/pub/shim/
grub2: https://koji.fedoraproject.org/koji/buildinfo?buildID=346715
kernel: http://koji.fedoraproject.org/koji/buildinfo?buildID=346864
linkReply

Comments:
[User Picture]From: cuviper
2012-08-09 07:29 pm (UTC)

(Link)

Non-root pesign for the Fedora build system sounds great, but how will that interact with the official cert? Surely we can't make that cert available to everyone using koji...
From: jwboyer
2012-08-10 01:04 pm (UTC)

(Link)

A great question. The plans for how signing will work with koji are still being worked out, but you are certainly correct in that not everyone will be able to build an officially signed Fedora kernel.

To emphasize again, my experimentation was just done with test/throwaway certs and some local patches. The final code for kernel signing might look slightly different than the patch I posted for kernel.spec.