Skip to content

Instantly share code, notes, and snippets.

@reillysiemens
Last active April 17, 2024 15:35
Show Gist options
  • Save reillysiemens/ac6bea1e6c7684d62f544bd79b2182a4 to your computer and use it in GitHub Desktop.
Save reillysiemens/ac6bea1e6c7684d62f544bd79b2182a4 to your computer and use it in GitHub Desktop.
Signing VirtualBox Kernel Modules

Signing VirtualBox Kernel Modules

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.

  1. 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
  2. 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 option openssl 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.

  3. 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.

  4. Reboot your machine to enter the MOK manager EFI utility.

    • Select Enroll MOK.

    Enroll MOK

    • Select Continue.

    Continue

    • Select Yes to enroll the keys.

    Confirm

    • Enter the password from earlier.

    Enter password

    • Select OK to reboot.

    Reboot

    • Verify the key has been loaded by finding the it in the output of
    dmesg | grep '[U]EFI.*cert'
  5. 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 the sign-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 on root's $PATH.

  6. Execute the aforementioned script as root.

    sudo chmod 700 /root/bin/sign-vbox-modules
    sudo -i sign-vbox-modules
  7. Load the vboxdrv module.

    sudo modprobe vboxdrv
@DylanMunyard
Copy link

I just realised the VirtualBox installer will sign the modules for you (at least on Ubuntu 22.04) but I didn't pick this up straight away because when I ran /sbin/vboxconfig I received the error that I needed to sign the modules. But there were no modules to sign!

My issue turned out to be I was missing make which was in the error message, but displayed after the message about signing the modules.

It actually mentions installing gcc, make and perl: sudo apt install gcc make perl -y

@peterborto
Copy link

peterborto commented Apr 3, 2023

Hi, fix work fine (edupr91 - version), on fedora 37

But there is a way not to ask key :

Passphrase for /root/module-signing/MOK.priv:

every reboot i need to insert it.

Thank you

@peterborto
Copy link

Hi,
updated to Fedora 38, same notice to insert passfrase

@vash83a
Copy link

vash83a commented May 10, 2023

@edupr91 @mmtechslv @fsimula @rfliam @cybusAlanFrancke @sirhennig Hi guys! I found this post because I've just updated to Fedora 36 and looked for a solution for the same issue. Everything you found out is true and I thank you a lot for everything, but I wanted tell you I've found a clever shortcut. During the issue investigation process, I found out the *.ko.xz modules were already signed by akmod. It was easily discoverable using modinfo. I was able to discover where the akmod keypair was stored and then I imported that public key in MOK . Doing that, my expectation is that everytime VirtualBox will be updated, the modules will be automatically loaded. So, signing modules everytime you upgrade Virtualbox it won't be needed anymore. I've never tested a VirtualBox upgrade process yet, because I've just installed the latest VirtualBox version. But, I can surely tell that the already signed modules by akmod work correctly.

What do you think about this solution?

The only thing that worries me is about the security perspective. The akmod private key is not password protected, so... just in case someone takes control of my machine, he/she could signs a malicious module using akmod. That module would be correctly loaded because that key had already been imported by me using MOK. Any consideration about that?

If you need more information fell free to ask. Thanks a lot.

I've just updated to fedora 37 and everything worked like a charm. the solution I found is really effective, I must say.

@PcChip
Copy link

PcChip commented Jun 19, 2023

this may be offtopic, but after spending an hour trying to get these modules signed on my Ubuntu 22.04 desktop, I realized that /sbin/vboxconfig was actually trying to build and sign them for me - however when viewing the log with cat /var/log/vbox-setup.log I saw that it was trying to run gcc-12 and I only had gcc-11 installed for some reason.

After installing gcc-12 and then re-running sudo /sbin/vboxconfig everything "just worked"!

@DylanMunyard
Copy link

this may be offtopic, but after spending an hour trying to get these modules signed on my Ubuntu 22.04 desktop, I realized that /sbin/vboxconfig was actually trying to build and sign them for me - however when viewing the log with cat /var/log/vbox-setup.log I saw that it was trying to run gcc-12 and I only had gcc-11 installed for some reason.

After installing gcc-12 and then re-running sudo /sbin/vboxconfig everything "just worked"!

Same thing I posted above https://gist.github.com/reillysiemens/ac6bea1e6c7684d62f544bd79b2182a4?permalink_comment_id=4491378#gistcomment-4491378. I spent hours trying to fix it following all the advice above, before reading the error telling me I didn't have the prerequisites installed. Hopefully more people see our posts and check this is not their issue before going down the rabbit hole.

@PcChip
Copy link

PcChip commented Jun 20, 2023

@DylanMunyard I actually tried what you listed as well: sudo apt install gcc make perl -y , however I already had those packages installed
For some reason it specifically wanted gcc-12! (possibly because I'm running the newest kernel and that was built with gcc-12?)

@apolloclark
Copy link

apolloclark commented Aug 2, 2023

I was able to fix this under Ubuntu 22.04 LTE, running the HWE (Hardware Enablement) stack with the latest kernel 5.19.0-50-generic, for Virtualbox 7.0.10r158379 with this command:

sudo mokutil --import /var/lib/shim-signed/mok/MOK.der

Check out this thread for Ubuntu: https://bugs.launchpad.net/ubuntu/+source/virtualbox/+bug/1992673

My understanding is that Secure Boot is a feature that allows manufacturers, OS creators, and users, to enroll signing keys MOK (Machine Owner Key), to enable various OSes to ensure they are running kernel and device driver code that has been signed by a trusted entity. Microsoft has a key it enrolls with popular manufacturers, but the various Linux distros do not. That "shim-signed" file is the private key for Ubuntu and Debian. That Linux MOK file needs to be manually trusted using mokutil.

I was able to get Virtualbox to temporarily run by following the instructions here, but after reboot, Virtualbox would still fail to load. What I found odd was that running sudo modprobe vboxdrv would give an error of modprobe: ERROR: could not insert 'vboxdrv'" Key was rejected by service. and in dmesg of Loading of module with unavailable key is rejected, despite the Virtualbox kernel modules being signed by a trusted MOK. I then realized that there was probably another MOK being used and ran find / -iname MOK.der to find the file /var/lib/shim-signed/mok/MOK.der, and read more about it.

You'll need to rerun that command if you do a BIOS update.

@ghatfan99
Copy link

Thank you very much for your help.
It works perfectly on debian 11

@oakyuz75
Copy link

Thanks, it works for Fedora 38 and Virtualbox 7.0.

Regards

@Zakys98
Copy link

Zakys98 commented Mar 1, 2024

For opensuse 15.5 I found that, you have to generate ssh keys with this command:
sudo openssl req -nodes -new -x509 -newkey rsa:2048 -outform DER -addext "extendedKeyUsage=codeSigning" -keyout /var/lib/shim-signed/mok/MOK.priv -out /var/lib/shim-signed/mok/MOK.der
In this command is addtext for code signing. With this key it worked fine.
Thanks for your guide.

@roopeshsn
Copy link

I am using Ubuntu 22.04. I followed the steps as mentioned but when ran sudo -i sign-vbox-modules, I am getting this error,

-bash: line 1: sign-vbox-modules: command not found

Could anyone help?

@iacchi
Copy link

iacchi commented Mar 18, 2024

I'm on Debian Sid and there's any easy (and more automatic way) to sign Virtualbox (and other) modules. This will probably apply to other Debian versions and possibly other distros. In Debian Virtualbox modules are already signed by dkms if compiled by installing the virtualbox-dkms package. The problem is that the key generated and used by dkms is not recognised in the system, so we need to add that particular one to MOK. If you go to /var/lib/dkms you should have a mok.pub and a mok.key file. If so, then issue the command:
mokutil --import /var/lib/dkms/mok.pub
and your pc will enroll the key used by dkms. This way all the modules built by the service will be able to load at startup and on every kernel update automatically.

@marcinpraczko
Copy link

This is super helpful this post finally helped me a lot with this issue which I tried to solve for many months. I knew what needs to be done, however many updates of system / bios upgraded / etc caused that my solutions didn't work any longer - and this post helped to solved. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment