Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
@reillysiemens

This comment has been minimized.

Copy link
Owner Author

@reillysiemens reillysiemens commented Feb 11, 2019

Aftermath

So, this didn't work as well as I would have liked for some reason... In attempting to sign these kernel modules again after a kernel update I hosed my system by corrupting my initramfs. Essentially, be careful. There be dragons here. 🐲

I ended up just disabling UEFI Secure Boot anyway. 🙃

@reinderien

This comment has been minimized.

Copy link

@reinderien reinderien commented Jun 4, 2019

This doesn't work at all for me, unfortunately. sign-file is in the wrong place:

~$ find /usr/src -name sign-file
/usr/src/linux-headers-4.15.0-50-generic/scripts/sign-file
@reillysiemens

This comment has been minimized.

Copy link
Owner Author

@reillysiemens reillysiemens commented Jun 5, 2019

@reinderien:

This doesn't work at all

seems uncharitable to me as I mentioned in the comment that

# The exact location of `sign-file` might vary depending on your platform.

I wrote this guide on Fedora, where it did work, but a different distro might place those files elsewhere as you said.

@reinderien

This comment has been minimized.

Copy link

@reinderien reinderien commented Jun 6, 2019

@agabopinho

This comment has been minimized.

Copy link

@agabopinho agabopinho commented Jun 29, 2019

Everything worked perfectly. Thank you!

@reillysiemens

This comment has been minimized.

Copy link
Owner Author

@reillysiemens reillysiemens commented Jun 29, 2019

Glad this helped you, @agabopinho! 😄

@RJColeman

This comment has been minimized.

Copy link

@RJColeman RJColeman commented Jul 28, 2019

I had to add this to the signing script:
export KBUILD_SIGN_PIN
Worked like a charm after that. Thank you so much for this!

@brasey

This comment has been minimized.

Copy link

@brasey brasey commented Aug 9, 2019

I had to add this to the signing script:
export KBUILD_SIGN_PIN
Worked like a charm after that. Thank you so much for this!

Yup, this worked for me too, thanks!

@noelalanguilan

This comment has been minimized.

Copy link

@noelalanguilan noelalanguilan commented Aug 21, 2019

I had to add this to the signing script:
export KBUILD_SIGN_PIN
Worked like a charm after that. Thank you so much for this!

Where did you put it in the script? I am new and just reading up about this before diving in.

@reillysiemens

This comment has been minimized.

Copy link
Owner Author

@reillysiemens reillysiemens commented Aug 21, 2019

@noelalanguilan: The best spot to add that is probably immediately after its definition

[ -z "${KBUILD_SIGN_PIN}" ] && read -p "Passphrase for ${key}: " KBUILD_SIGN_PIN

like

[ -z "${KBUILD_SIGN_PIN}" ] && read -p "Passphrase for ${key}: " KBUILD_SIGN_PIN
export KBUILD_SIGN_PIN

This is actually a mistake on my part and I'll correct it in the Gist. I had KBUILD_SIGN_PIN already defined in my environment, so the first part of the expression short circuits the call to read and the environment variable passes right on through to sign-file.

In the case of these other folks though, they probably didn't have it defined in the parent environment, so when read prompts for it it's defined within that scope, but not exported so that sign-file can access it. Basically, it's necessary to export when prompted for and won't hurt if it's already defined.

@reillysiemens

This comment has been minimized.

Copy link
Owner Author

@reillysiemens reillysiemens commented Aug 21, 2019

The absent

export KBUILD_SIGN_PIN

has been included in the Gist now. Thanks, @RJColeman.

@mikfra

This comment has been minimized.

Copy link

@mikfra mikfra commented Aug 22, 2019

Using Fedora30:Kern-5.2.9 I had to take additional steps to compile the vbox kernel modules.

mv /usr/share/virtualbox/src/vboxhost/* /lib/modules/5.2.9-200.fc30.x86_64/misc/
make && make install
/root/bin/sign-vbox.sh

modified line for module in $(dirname $(modinfo -n vboxdrv))/.k to for module in $(dirname $(modinfo -n vbox*))/.k

modprobe vboxdrv

*Was able to boot a VM after modprobe vboxdrv

  • Ran into errors for the other Vboxpci modules. Assuming my Motherboard may not have IOMMU or vt-d support. Not to familiar with Virtual Box. Spoiled with VMware all my life lol
    Cheers, Hope this helps!
@raul1991

This comment has been minimized.

Copy link

@raul1991 raul1991 commented Oct 16, 2019

PKCS#7 signature not signed with a trusted key

I am getting this error after running the script.

@hoxsiew

This comment has been minimized.

Copy link

@hoxsiew hoxsiew commented Oct 31, 2019

Could you elaborate some on step 4? I don't get a "MOK manager EFI utility" upon reboot, just a normal bootup.

@raul1991

This comment has been minimized.

Copy link

@raul1991 raul1991 commented Nov 1, 2019

I re-imported the MOK and it worked fine.

@hoxsiew

This comment has been minimized.

Copy link

@hoxsiew hoxsiew commented Nov 1, 2019

I tried that before and got a message that the MOK was already in the enrollment request.

@Jerczey

This comment has been minimized.

Copy link

@Jerczey Jerczey commented Nov 14, 2019

well u rock, here's a star or whatever is a 'Like' on this :)

@chipmunk03

This comment has been minimized.

Copy link

@chipmunk03 chipmunk03 commented Nov 27, 2019

Hi Reillysiemens,

thanks for this helpful script. I adjusted it a little for my distribution (elementary), which is a Debian/Ubuntu based GNU Linux distro. I want to share it with you, so it might work on other distributions as well.

Add above this line in reillysiemens script
[ -z "${KBUILD_SIGN_PIN}" ] && read -p "Passphrase for ${key}: " KBUILD_SIGN_PIN

this piece of code:

# source /etc/os-release
. /etc/os-release

# The exact location of sign-file" might vary depending on your platform.

case ${ID_LIKE} in
       "rhel centos") alias sign-file="/usr/src/kernel/$(uname -r)/scripts/sign-file"
                ;;
        "debian" | "ubuntu") alias sign-file="/usr/src/linux-headers-$(uname -r)/scripts/sign-file"
                ;;
#       "ubuntu") alias sign-file="/usr/src/linux-headers-$(uname -r)/scripts/sign-file"
#               ;;
        *) echo "Unknown distribution"
           exit 99
esac

If you have only one kernel version installed, you can use the find method like this
alias sign-file="$(find /usr/src -name sign-file)"
I have more than one kernel versions installed, so this does not work for me. I use the 'case' construct instead.

Cheers.

@cierzniak

This comment has been minimized.

Copy link

@cierzniak cierzniak commented Dec 1, 2019

Debian 10.2 (kernel from backports)

$ dpkg -S sign-file
linux-kbuild-5.3: /usr/lib/linux-kbuild-5.3/scripts/sign-file
linux-kbuild-4.19: /usr/lib/linux-kbuild-4.19/scripts/sign-file
$ sudo find /usr/src -name sign-file
$ sudo find /usr/lib -name sign-file
/usr/lib/linux-kbuild-4.19/scripts/sign-file
/usr/lib/linux-kbuild-5.3/scripts/sign-file
@Prashy27

This comment has been minimized.

Copy link

@Prashy27 Prashy27 commented Dec 19, 2019

A very useful article! Steps were very clear and informative.

@AlekseyPn

This comment has been minimized.

Copy link

@AlekseyPn AlekseyPn commented Dec 19, 2019

Thanks!!! I finally victory!!! :D

@alexhanssens

This comment has been minimized.

Copy link

@alexhanssens alexhanssens commented Jan 1, 2020

after entering the first command under 2:
name="$(getent passwd $(whoami) | awk -F: '{print $5}')"
I get " Illegal variable name"
I do something wrong?

@m4ldonado

This comment has been minimized.

Copy link

@m4ldonado m4ldonado commented Jan 2, 2020

Thanks!

The MOK manager EFI utility didn't load for me on Fedora 31 because the shim had lower boot priority. Solution:

  1. copy the boot order from efibootmgr -v putting the number of the shim first
  2. efibootmgr -o [boot order you copied]
@4levels

This comment has been minimized.

Copy link

@4levels 4levels commented Jan 28, 2020

You saved my life many times (again just now) with this gist, after every major OS update on Debian I keep coming back to this!

@reillysiemens

This comment has been minimized.

Copy link
Owner Author

@reillysiemens reillysiemens commented Jan 31, 2020

@alexhanssens: If you're not using a Bash-like shell, for example csh or tcsh, then you might encounter an error like that. If that's the case, then you might have better luck with something like

setenv name `getent passwd $USER | awk -F: '{print $5}'`
@RailRunner166

This comment has been minimized.

Copy link

@RailRunner166 RailRunner166 commented Feb 6, 2020

hey all, hopefully you can offer some assistance on an issue ive been having.
I have reached step three and have imported the mok, however when i restart my computer (i'm running arch just in case this is an arch thing) it doesn't show the blue screen...
Any ideas?

Thanks

@reillysiemens

This comment has been minimized.

Copy link
Owner Author

@reillysiemens reillysiemens commented Feb 8, 2020

@RailRunner166: I don't run Arch myself, so I've no immediate suggestions, but the Arch Wiki page on Secure Boot seems pretty detailed. Interestingly I couldn't find mention of mokutil anywhere on that page, so maybe they recommend a different approach.

@reillysiemens

This comment has been minimized.

Copy link
Owner Author

@reillysiemens reillysiemens commented Feb 10, 2020

@RailRunner166: Thinking about it a little more, maybe @m4ldonado's comment has something to do with your troubles. Might be worth looking into that angle.

@RailRunner166

This comment has been minimized.

Copy link

@RailRunner166 RailRunner166 commented Feb 11, 2020

Eh, it turned out I didn't even need to sign my modules at all 😆 (secure boot was off) so uh, thanks anyway 😄

@ChrisRoald

This comment has been minimized.

Copy link

@ChrisRoald ChrisRoald commented Mar 14, 2020

Hi,
After reinstalling the virtualbox module virtualbox-dkms using synaptic, I get a dialog that asks me to enter and verify a pass-key that'll be used in MOK management when I reboot. But MOK Management isn't listed in my reboot screen; nor does it appear automatically. Is there something additional I need to do, either in or after the synaptic module reinstall, to get MOK working at reboot?
Thanks

@rpgdev

This comment has been minimized.

Copy link

@rpgdev rpgdev commented Apr 24, 2020

Worked on Fedora 32. Had to boot to an older kernel because of kernel-devel package not being available to newest kernel but other than that the process went smoothly. Thank you!

@joshisaurabh2002

This comment has been minimized.

Copy link

@joshisaurabh2002 joshisaurabh2002 commented Apr 27, 2020

I have oracle-linux 7 and the above steps smoothly worked for me. 👍

@gvisoc

This comment has been minimized.

Copy link

@gvisoc gvisoc commented May 12, 2020

Debian 10.2 (kernel from backports)

$ dpkg -S sign-file
linux-kbuild-5.3: /usr/lib/linux-kbuild-5.3/scripts/sign-file
linux-kbuild-4.19: /usr/lib/linux-kbuild-4.19/scripts/sign-file
$ sudo find /usr/src -name sign-file
$ sudo find /usr/lib -name sign-file
/usr/lib/linux-kbuild-4.19/scripts/sign-file
/usr/lib/linux-kbuild-5.3/scripts/sign-file

For Debian 10 there are a few changes to make this work. First, we have to trim some of the version numbers of the uname -r output, and change the location of the sign-file. Debian 10 also removes the modinfo from the root PATH by default, hence a small modification to use /sbin/modinfo instead. I made these changes to this awesome gist.

#!/bin/sh

readonly hash_algo='sha256'
readonly key='MOK.priv'
readonly x509='MOK.der'

readonly name="$(basename $0)"
readonly esc='\\e'
readonly reset="${esc}[0m"
readonly fullver=$(uname -r)
readonly majorminor="$(echo $fullver | cut -d '.' -f1,2)"

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.
# This is for Debian
alias sign-file="/usr/lib/linux-kbuild-${majorminor}/scripts/sign-file"

[ -z "${KBUILD_SIGN_PIN}" ] && read -p "Passphrase for ${key}: " KBUILD_SIGN_PIN
export KBUILD_SIGN_PIN

# In Debian, modinfo is not in the PATH even for root users. In other 
# distributions it may not be located at /sbin
for module in $(dirname $(/sbin/modinfo -n vboxdrv))/*.ko; do
  log "Signing $(green ${module})..."
  sign-file "${hash_algo}" "${key}" "${x509}" "${module}"
done

I plan to extend it a bit to work with any module, it's very handy. Kudos to @reillysiemens

@scantisani

This comment has been minimized.

Copy link

@scantisani scantisani commented May 15, 2020

On Fedora 31 (kernel version 5.6.11-200.fc31.x86_64), modprobe was responding with modprobe: ERROR: could not insert 'vboxdrv': Bad message when I tried to load the VirtualBox modules.

I re-generated MOK.priv and MOK.der by following the key generation instructions in the official Fedora 31 docs, then re-signed the modules. Then everything worked fine.

@tomberlin55

This comment has been minimized.

Copy link

@tomberlin55 tomberlin55 commented Aug 7, 2020

I have NO *.ko files on my server.
Running nethserver (Centos).
tried to install
VirtualBox-6.1-6.1.12_139181_el7-1.x86_64.rpm
I managed to install the MOK to my BIOS, I found the sign thing, but I have not on .ko file on my whole computer...

@JJ

This comment has been minimized.

Copy link

@JJ JJ commented Aug 16, 2020

Slight change for Ubuntu:

alias sign-file="/usr/src/linux-headers-$(uname -r)/scripts/sign-file"
@JJ

This comment has been minimized.

Copy link

@JJ JJ commented Aug 16, 2020

This doesn't work at all for me, unfortunately. sign-file is in the wrong place:

~$ find /usr/src -name sign-file
/usr/src/linux-headers-4.15.0-50-generic/scripts/sign-file

This worked for me. Thanks!

@jk-1

This comment has been minimized.

Copy link

@jk-1 jk-1 commented Oct 13, 2020

Slight change for Ubuntu:

alias sign-file="/usr/src/linux-headers-$(uname -r)/scripts/sign-file"

This worked on Ubuntu 20.04, Thanks!!!

@jkufner

This comment has been minimized.

Copy link

@jkufner jkufner commented Oct 13, 2020

Important detail: If you have a system without Shim, using only Sicherboot or booting the kernel directly, and using your own keys (SecureBoot in the user mode), then you can use db.key instead of the missing MOK key. Therefore:

 find "$module_dir" -type f -name "*.ko" \
        -fprint /dev/stderr \
        -exec "$sign_file" sha256 /etc/sicherboot/keys/db.key /etc/sicherboot/keys/db.cer '{}' \;

See also: julian-klode/sicherboot#11

@GoetzEdinger

This comment has been minimized.

Copy link

@GoetzEdinger GoetzEdinger commented Oct 21, 2020

Great Job!
It worked on Fedora 32 after the first 4 steps.
Thank You!

@zaid20485

This comment has been minimized.

Copy link

@zaid20485 zaid20485 commented Oct 23, 2020

Thank you
worked for me , on fedora 32

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.