These are the steps I followed enable VirtualBox on my laptop without disabling UEFI Secure Boot. They're nearly identical to the process described on Øyvind Stegard's blog, save for a few key details. The images here are borrowed from the Systemtap UEFI Secure Boot Wiki.
-
Install the VirtualBox package (this might be different for your platform).
src='https://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo' dst='/etc/yum.repos.d/virtualbox.repo' sudo curl ${src} > ${dst} dnf check-update sudo dnf install VirtualBox-6.0
-
Create an RSA key pair to sign kernel modules.
name="$(getent passwd $(whoami) | awk -F: '{print $5}')" out_dir='/root/module-signing' sudo mkdir ${out_dir} sudo openssl \ req \ -new \ -x509 \ -newkey \ rsa:2048 \ -keyout ${out_dir}/MOK.priv \ -outform DER \ -out ${out_dir}/MOK.der \ -days 36500 \ # This is probably waaay too long. -subj "/CN=${name}/" sudo chmod 600 ${out_dir}/MOK*
Note the absence of the
-nodes
option from Øyvind's post. With this optionopenssl
will create a private key with no passphrase. The omission of this option prompts for a passphrase, which seems like a good idea for something as important as a kernel module signing key. -
Import the MOK ("Machine Owner Key") so it can be trusted by the system.
sudo mokutil --import /root/module-signing/MOK.der
This will prompt for a password. The password is only temporary and will be used on the next boot. It does not have to be the same as the signing key passphrase.
-
Reboot your machine to enter the MOK manager EFI utility.
- Select Enroll MOK.
- Select Continue.
- Select Yes to enroll the keys.
- Enter the password from earlier.
- Select OK to reboot.
- Verify the key has been loaded by finding the it in the output of
dmesg | grep '[U]EFI.*cert'
-
Create a script for signing all the VirtualBox kernel modules.
#!/bin/sh readonly hash_algo='sha256' readonly key='/root/module-signing/MOK.priv' readonly x509='/root/module-signing/MOK.der' readonly name="$(basename $0)" readonly esc='\\e' readonly reset="${esc}[0m" green() { local string="${1}"; echo "${esc}[32m${string}${reset}"; } blue() { local string="${1}"; echo "${esc}[34m${string}${reset}"; } log() { local string="${1}"; echo "[$(blue $name)] ${string}"; } # The exact location of `sign-file` might vary depending on your platform. alias sign-file="/usr/src/kernels/$(uname -r)/scripts/sign-file" [ -z "${KBUILD_SIGN_PIN}" ] && read -p "Passphrase for ${key}: " KBUILD_SIGN_PIN export KBUILD_SIGN_PIN for module in $(dirname $(modinfo -n vboxdrv))/*.ko; do log "Signing $(green ${module})..." sign-file "${hash_algo}" "${key}" "${x509}" "${module}" done
This script differs from Øyvind's in two aspects. First, and most importantly, it has ✨ C O L O R S ✨. Second, it uses the magic
$KBUILD_SIGN_PIN
environment variable that doesn't appear anywhere in thesign-file
usage. I went spelunking in the Linux source for it, but in hindsight I could have just read the docs on manual module signing... I wrote this script to/root/bin/sign-vbox-modules
as that's usually onroot
's$PATH
. -
Execute the aforementioned script as
root
.sudo chmod 700 /root/bin/sign-vbox-modules sudo -i sign-vbox-modules
-
Load the
vboxdrv
module.sudo modprobe vboxdrv
Thanks, it works in Ubuntu 20.04.
One small improvement: print $1 to get username
name="$(getent passwd$(whoami) | awk -F: '{print $ 1}')"