Tuesday, 22 May 2018

UEFI Secure Boot: Signing kernel modules (Linux - Ubuntu)


After many times setting up different virtual labs by means of different hypervisors, such as Vmware Player and Virtualbox, there was once that I got struggled with starting up my already configured virtual machines and make their network capabilities work. After a little bit of investigation through Google along and thanks to the different output errors and my years of experience using Linux systems I realized that the "problem" was something called UEFI Secure Boot or Trusted Boot. Briefly, Secure Boot is simply a verification mechanism that takes place during the start-up process with the aim to prevent malicious code of being loaded and therefore to gain access to the computer. It just allows to load components trusted by the manufacturer or the user, i.e., signed binaries and kernel modules that are already signed by trusted keys. The term UEFI (Unified Extensible Firmware Interface) is basically the surrogate of the old and well-known BIOS (Basic Input/Output System) which includes such validation mode.

Throughout this article I will follow the same problem I faced when trying to launch my virtual machines. Moreover, I want to point out that this article is focused exclusively on signing kernel modules rather than other components, such as kernels, bootloaders, etc. I won't dive into many of the underlying concepts in detail, such boot process, key databases, machine owner keys (MOK), shim, certificates, cryptographic keys, etc. (just google it if you feel inquisitive). Some of those concepts will just be mentioned and others briefly explained for a better understanding.

Firstly and briefly, secure boot feature appeared in Windows 8 presinstalled computers. Ubuntu 64-bit versions support it as well. In few words, the concept of secure boot in Ubuntu requires the existence of  a chain of trust from the very first thing loaded (firmware), all the way through to components load by the O.S as part of the kernel, such as modules:

  1. Root certificate (Microsoft) used to validate the shim binary.
  2. A Canonical certificate along with a trust database is embedded in the shim. Such certificate is used to validate further components (bootloader) signed with the corresponding Canonical key. Everything else falling aside will require to be self-signed by the user herself.
  3. Further signed components (GRUB binary, kernel, modules, etc.) will be validated against the trust database (any component signed with any trusted key is considered official/trusted in the Ubuntu realm and therefore it won't be refused). For instance, in order to load a kernel this must be signed to be allowed to load by GRUB (default bootloader) when secure boot is enabled. Disabling validation in shim as well as own signing process are two solutions to allow unsigned kernels to be loaded. 
The origin of the problem was that some critical kernel modules needed to properly run Virtualbox were not loaded into the kernel upon deman. But why?


The reason why is what I've earlier explained. Such modules are considered third-party/unofficial modules because they are not signed by any trusted key (neither Canonical's UEFI key) and from Ubuntu 16.04 is required that all the kernel modules are signed to be loaded during the start-up time (only if Secure Boot is enabled). Thus, when booting up my laptop with the secure boot enabled it was not possible to load those modules during the start-up process due to unsigned modules are refused as well as modules signed with untrusted keys (keys that are not contained in the trust database). If you try to insert those modules with modprob the process will just fail.


Third-party drivers are not compatible with Secure Boot enabled. Regardless, there are some possible ways to overcome this problem:
  1. Disable the secure boot.
  2. Do not use third-party drivers.
  3. Sign those third-party modules.
The first solution is as simple as either disabling the Secure Boot mode through the PC's firmware menus or by just typing the following command and reboot the PC:

$ sudo mokutils --disable-validation

Disabling secure boot might be seen as the simplest solution. The weak spot of this fix is that your PC becomes more vulnerable and therefore the attack surface grows. Depending on the scenario you are facing it might be necessary to do so.

The second solution is not worth it at all. Avoiding third-party software is just foolish. At some point you will need to make use of "unofficial" software whatever your needs/motives. The non-use of third-party software is not even a choice to keep in mind.

Finally, although the last solution is the most confusing among the 3 solutions previously proposed, it is the most coherent one. Before starting to sign kernel modules it is necessary to create a Self Signed Certificate for module self-signing. The private key is generated simultaneously and the public key is part of the certificate itself:

$ openssl req -new -x509 -newkey rsa:2048 -keyout VIRTUALBOX.priv -outform DER -out VIRTUALBOX.der -nodes -days 36500 -subj "/CN=Virtualbox/

Once the public certificate and the private key are created, I would recommend you to keep both in a secure location (encrypted external storage if possible) and change their access permissions. Specially the private key should be well-protected because if an attacker succeeds in getting your key she will be able to generate binaries and therefore sign them. Your PC would accept them as trustworthy.

The next step to follow is to enroll the public key certificate, i.e, the .der file in the shim. The MOK utility is in charge to manage the use of user-provided keys in the trust of chain. The machine owner keys are keys that users generate to sign binaries and thus give them the ability to run, in this case, third-party kernel modules (it could also be bootloaders not delivered by the distribution maintaner, locally-compiled kernels, etc.). To enroll a key in the shim simply issue the following command and reboot (shim will display a blue screen before loading GRUB). Verify that the key has been enrolled afterwards:

$ sudo mokutil --import VIRTUALBOX.der
$ sudo cat /proc/keys 
Shim UEFI Key Managemen

All right, let's go now to sign things. In order to sign the kernel module there is a fabulous and handy tool in Linux called kmodsign (it only signs loadable kernel modules rather than kernels or bootloaders). We need the two keys previously generated and find out where the module is located. Loadable kernel modules have the .ko extensions at the end of their names.

$ sudo find / -name vboxdrv.ko

$ sudo kmodsign sha512 VIRTUALBOX.priv VIRTUALBOX.der /lib/modules/$(uname -r)/misc/vboxdrv.ko

CONGRATULATIONS 😋! Try to launch again your virtual machines to verify that the old output error doesn't longer appear.

References:

https://blog.ubuntu.com/2017/08/11/how-to-sign-things-for-secure-boot

http://www.rodsbooks.com/efi-bootloaders/secureboot.html#preloader


https://wiki.gentoo.org/wiki/Signed_kernel_module_support

https://wiki.ubuntu.com/UEFI/SecureBoot



  

No comments:

Post a Comment