Systemtap UEFI Secure Boot Support

Systemtap release 2.5 contains UEFI Secure Boot support.. This new functionality lets systemtap work on systems with secure boot set up in their UEFI firmware. There are actually several different keys sets involved in the UEFI Secure Boot functionality. We're going to add the a public certificate to the MOK (Machine Owner Keys) database that systemtap will use to sign modules.

Here's how the new functionality works. In short, the systemtap compile server has been taught to sign modules with a MOK (Machine Owner Key) that it has in common with a client system. Then, compiling and running modules is the same as running on a non-secure boot system.

Systemtap automatically detects the presence of UEFI SecureBoot activation using /proc or /sys files. Some fedora kernels hide this, so a manual workaround is needed (setting the SYSTEMTAP_SIGN environment to 1).

Here's the long version of how this works. First, you'd need a system with UEFI firmware with secure boot turned on. If you don't have such a system, you can build a virtual machine with UEFI firmware. For details, see the following Fedora wiki page:

https://fedoraproject.org/wiki/Testing_secureboot_with_KVM

The first thing to do is set up a systemtap compile server (or use an existing one if you have one) that includes commit c813433. The systemtap compile server system can be on the same system as your client or a different system. Assuming your server is up and running, here we go. On the client system, try listing systemtap compile servers:

# stap --list-servers
Systemtap Compile Server Status for 'online,trusted,compatible'
No servers found

Notice we didn't find any trusted, compatible, online servers. This is actually to be expected. The client is now smart enough to know that it needs MOK signed modules, and gets a list of MOKs that the server can sign modules with. The client compares the list of server MOKs to the list of MOKs installed on the client. Since at this point the server and client don't have any MOKs in common, the client and server aren't compatible.

So, let's fix that. We could create a MOK by hand and install it on the client and server. But, the easier way is to let the systemtap compile server send us a MOK to install on the client. First, we'll need to find the server:

# stap --list-servers=all
Systemtap Compile Server Status for 'all'
 host=kvm-rawhide-64-uefi-1.local address=10.15.1.3 port=39587 sysinfo="3.14.0-0.rc2.git4.1.fc21.x86_64 x86_64" version=2.5 certinfo="00:9e:56:9b:5e"

Now that we know the host name ('kvm-rawhide-64-uefi-1.local') and port number (39587), we can ask that server to compile a module for us:

# stap --use-server=kvm-rawhide-64-uefi-1.local:39587 -e 'probe begin { exit() }'
Server: No matching machine owner key (MOK) available on the server to sign the module.
Server: The server has no machine owner key (MOK) in common with this system. Use the following command to import a server MOK into this system, then reboot:

        mokutil --import signing_key.x509
Passes: via server failed.  Try again with another '-v' option.

The server realized that it and the client had no MOK in common. So, it generated a new MOK (if necessary), and sent the public certificate down to the client. In this case the server didn't have any existing MOKs, so it had to generate a new one. So, as the message says above, we have to use 'mokutil' as root to add this new MOK to the UEFI firmware.

# mokutil --import signing_key.x509
 input password:
 input password again:

If the UEFI firmware doesn't have a MOK password, mokutil will ask you to create one here. At this point, you'll need to reboot the client system. Upon reboot, you'll see something like the following. The following screenshots are from the OVMF firmware. Each vendor's firmware will be a little different, but the steps should be similar. First, go down to 'Enroll Mok':

Screenshot_kvm-rawhide-64-uefi-1_2014-02-27_14:00:13_crop.png

Then the firmware gives you the option of viewing the new MOK or continuing. Let's continue.

Screenshot_kvm-rawhide-64-uefi-1_2014-02-27_14:00:35_crop.png

It then asks you to to confirm enrollment.

Screenshot_kvm-rawhide-64-uefi-1_2014-02-27_14:00:44_crop.png

Then you will need to enter the password you used when running 'mokutil --import'.

Screenshot_kvm-rawhide-64-uefi-1_2014-02-27_14:00:53_crop.png

Finally, the firmware will ask you to reboot.

Screenshot_kvm-rawhide-64-uefi-1_2014-02-27_14:01:06_crop.png

Here's a note about running a VM with the OVMF UEFI firmware. Right now, there is no persistent storage for the OVMF UEFI firmware in qemu. So, if you power down your VM, you'll have to reinstall the MOKs. This bug/missing feature is being worked on upstream in qemu.

After the reboot, you can run 'mokutil --list-enrolled' to see the new key:

# mokutil --list-enrolled | egrep -i 'SHA1|Issuer'
SHA1 Fingerprint: 1f:52:31:74:bb:46:94:02:54:d7:bb:42:26:e6:cb:8f:fd:52:89:c1
        Issuer: O=Systemtap, CN=Systemtap module signing key
SHA1 Fingerprint: 7e:68:65:1d:52:68:5f:7b:f5:8e:a0:1d:78:4d:2f:90:d3:f4:0f:0a
        Issuer: CN=Fedora Secure Boot CA
                CA Issuers - URI:https://fedoraproject.org/wiki/Features/SecureBoot

After the reboot, when we list servers, the compile server will show up as compatible, since the client and server have a MOK in common:

# stap --list-servers
Systemtap Compile Server Status for 'online,trusted,compatible'
 host=kvm-rawhide-64-uefi-1.local address=10.15.1.3 port=36138 sysinfo="3.14.0-0.rc2.git4.1.fc21.x86_64 x86_64" version=2.5 certinfo="00:9e:56:9b:5e" mok_fingerprints="1f:52:31:74:bb:46:94:02:54:d7:bb:42:26:e6:cb:8f:fd:52:89:c1"

OK, let's try to compile and run a module now:

# stap -ve 'probe begin { printf("hello\n"); exit() }'
Using a compile server.
Pass 1: parsed user script and 100 library script(s) using 211876virt/29220res/2984shr/26476data kb, in 200usr/100sys/506real ms.
Pass 2: analyzed script: 1 probe(s), 1 function(s), 0 embed(s), 0 global(s) using 212404virt/29996res/3228shr/27004data kb, in 10usr/0sys/31real ms.
Pass 3: translated to C into "<server>/stap000000/stap_e8600a4143178ae7777f6ff068e92399_1018_src.c" using 212528virt/30164res/3372shr/27128data kb, in 0usr/0sys/3real ms.
Pass 4: compiled C into "stap_e8600a4143178ae7777f6ff068e92399_1018.ko" in 2510usr/2180sys/8643real ms.
Server: Module signed with MOK, fingerprint "1f:52:31:74:bb:46:94:02:54:d7:bb:42:26:e6:cb:8f:fd:52:89:c1"
Passes: via server  host=kvm-rawhide-64-uefi-1.local address=0.0.0.0 port=36138 sysinfo="3.14.0-0.rc2.git4.1.fc21.x86_64 x86_64" version=2.5 certinfo="00:9e:56:9b:5e" mok_fingerprints="1f:52:31:74:bb:46:94:02:54:d7:bb:42:26:e6:cb:8f:fd:52:89:c1" using 191072virt/5456res/4360shr/1036data kb, in 10usr/60sys/11052real ms.
Pass 5: starting run.
hello
Pass 5: run completed in 30usr/190sys/620real ms.

Once the client and server have a MOK in common, compiling and running modules is fairly transparent. Notice we didn't have to use the '--use-server' option, the client realized that since it requires MOK signed modules, it must use a compile server.

Manually Creating Secure Boot Modules

If you'd like to create a signed module by hand, here are the steps you'd go through.

First, create a set of MOK keys. Run the following command (using systemtap's 'x509.genkey' config file) :

# openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \
    -config x509.genkey -outform DER -out signing_key.x509 \
    -keyout signing_key.priv

That generates 'signing_key.x509' and 'signing_key.priv'.

Then, install the key on the server as described above by running

mokutil --import signing_key.x509

Then create and sign the module:

# stap -m hello -vp4 -e 'probe begin { printf("hello\n"); exit() }'
# /usr/src/kernels/`uname -r`/scripts/sign-file sha512 signing_key.priv
signing_key.x509 hello.ko

None: SecureBoot (last edited 2018-11-12 14:41:06 by FChE)