在启用 EFI 安全启动的情况下对 Virtualbox 模块进行签名

Adr*_*uso 7 virtualbox uefi

我有一个带有 Nvidia 卡并启用了 EFI 安全启动的系统 (22.04.1 LTS)。

Virtualbox 拒绝运行虚拟机并声称“如果系统启用了 EFI 安全启动,您可能还需要签署内核模块(vboxdrv、vboxnetflt、vboxnetapd、vboxpci)”

“VERR_VM_DRIVER 未安装”

我如何签署这些模块?

Rod*_*ith 7

首先,问题不在于EFI;它具有安全启动功能,这只是 UEFI 的一项特定功能。安全启动可以启用或禁用,甚至在某些(大多数是较旧的)EFI/UEFI 实现中不存在。我提到这一点是因为,如果您可以编辑问题的标题,这样做会对其他人有所帮助。

其次,要回答您的问题,您必须首先在计算机中安装安全启动计算机所有者密钥 (MOK) 或安全启动数据库密钥。为此,您必须安装opensslmokutil程序(分别来自opensslmokutil软件包)。简单来说:

  1. 使用 shell(终端程序或文本模式登录)创建临时目录并将其更改为临时目录。

  2. 创建一个 MOK。这是通过发出两个命令来完成的:

    openssl req -new -x509 -newkey rsa:2048 -keyout MOK.key -out MOK.crt -nodes -days 3650 -subj "/CN=Your Name/"
    openssl x509 -in MOK.crt -out MOK.cer -outform DER
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将此 MOK 安装到计算机的 NVRAM 中。这可以通过多种方式完成,但最简单的可能是使用mokutil. 首先将MOK.cer文件传递给mokutil

    sudo mokutil -i MOK.cer
    
    Run Code Online (Sandbox Code Playgroud)
  4. 请注意,sudo可能会要求您提供账户密码;然后mokutil将要求输入密码并进行确认。

  5. 重新启动计算机。如果一切顺利,系统会要求您按一个键开始 MOK 管理,然后要求输入密码 - 输入您提供的mokutil密码。(在我最近的一些实验中,系统要求从密码中输入特定的随机字符,这比较尴尬。)然后您可以确认将 MOK 添加到 NVRAM 的 MOK 列表中。完成后,重新启动进入 Ubuntu。

现在 MOK 存储在 NVRAM 中,您可以对 VirtualBox 驱动程序二进制文件进行签名。在最基本的形式中,执行此操作的命令是:

$path_to_binary/sign-file sha256 MOK.key MOK.cer $path_to_driver/vboxdrv.ko
Run Code Online (Sandbox Code Playgroud)

vboxnetadp.ko对和重复此操作vboxnetflt.ko。该sign-file程序实际上是Linux内核源代码的一部分;它不是 Ubuntu 中的标准程序。您可以通过键入 找到它的位置find /usr/src -iname sign-file。如果尚未安装,则应安装该linux-headers软件包。find如果您还不知道,您还可以使用来查找 VirtualBox 模块的位置。

模块签名后,您可以加载它们modprobe或重新启动计算机。

我经常这样做,以至于我编写了一个脚本来自动执行该过程的签名部分。不过,此脚本不会自动创建 MOK。这是我的脚本:

#!/bin/bash
# sign-vbox script, copyright (c) 2017 by Rod Smith
# Distributed under the terms of the GPLv3

if [ "$#" -ne 1 ] && [ "$#" -ne 0 ]; then
    echo "Usage: $0 [ {kernel-version} ]"
    exit 1
fi

if [ "$#" == 0 ]; then
    kernel_version=$(uname -r)
#    apt-get install virtualbox-dkms --reinstall
else
    kernel_version="$1"
fi

sign_file=$(find /usr/src/ -name sign-file | tail -n 1)

if [ -z $sign_file ]; then
    echo "Can't find the sign-file binary! Exiting!"
    exit 1
else
    path_to_modules="/lib/modules/$kernel_version/updates/dkms"

    if [ ! -f $path_to_modules/vboxdrv.ko ]; then
        echo "Could not find $path_to_modules/vboxdrv.ko!"
        echo "Is the kernel version correct?"
        exit 1
    fi

    echo "Signing modules for $kernel_version"
    $sign_file sha256 /mnt/keys/MOK.key /mnt/keys/MOK.cer $path_to_modules/vboxdrv.ko
    $sign_file sha256 /mnt/keys/MOK.key /mnt/keys/MOK.cer $path_to_modules/vboxnetadp.ko
    $sign_file sha256 /mnt/keys/MOK.key /mnt/keys/MOK.cer $path_to_modules/vboxnetflt.ko
    modprobe vboxdrv
    modprobe vboxnetflt
    modprobe vboxpci
    modprobe vboxnetadp
    echo "Loaded vbox modules:"
    lsmod | grep vbox
fi
Run Code Online (Sandbox Code Playgroud)

要使用该脚本,首先将其存储在文件中并使其可执行(chmod a+x sign-vbox例如,如果这是您使用的文件名)。然后,您可以执行该脚本root,如 中所示sudo ./sign-vbox。这将对当前启动的内核的 VirtualBox 模块进行签名。(如果您想签署另一个内核的模块,您可以将其版本号作为选项传递。)此外,该脚本对关键文件使用硬编码位置,这使我们......

请注意,该MOK.key文件(或无论您如何称呼它)可能非常敏感。如果入侵者获得了该密钥,那么入侵者就可以对内核模块或引导加载程序进行签名,并使用它来对您的计算机进行非常低级别的访问。这就是该脚本访问 ; 中的关键文件的原因/mnt/keys。我们的想法是将它们放在可移动磁盘上,并仅在需要时才安装该磁盘。以这种方式存储之前生成的所有密钥openssl。根据需要调整脚本以适应您存储密钥的位置。