为什么在安装第三方内核模块或升级内核后会出现“所需密钥不可用”的错误提示?

这个问题只发生在启用了安全启动的UEFI系统上。
当我尝试安装像VirtualBox、Nvidia或Broadcom驱动程序这样的DKMS模块时,它们无法安装,并且在我尝试使用modprobe命令时出现“Required key not available”的错误。
VirtualBox抱怨vboxdrv未加载。
Broadcom的wl驱动程序在lspci -k中显示为内核模块,但未被使用。sudo modprobe wl会抛出“Required key not available”的错误。
当我从git源安装一些内核模块时,也可能出现这个问题。
这个问题可能在内核更新后出现,如禁用的无线适配器、重新启动后的黑屏等。
我该如何解决这个问题?

类似的问题:https://askubuntu.com/questions/760671/could-not-load-vboxdrv-after-upgrade-to-ubuntu-16-04-and-i-want-to-keep-secur - Tor Klingberg
https://stackoverflow.com/a/59536913/3291390 - Stack Underflow
5个回答

自Ubuntu内核4.4.0-20开始启用了EFI_SECURE_BOOT_SIG_ENFORCE内核配置。如果UEFI安全启动被启用,这将阻止加载未签名的第三方模块。

修复此问题的最简单方法是在UEFI(BIOS)设置中禁用安全启动

在大多数情况下,您可以使用grub菜单进入UEFI设置。在启动时按ESC按钮,进入grub菜单,选择系统设置。安全启动选项应位于UEFI的“安全”或“引导”部分。

您也可以直接进入UEFI,但这取决于您的硬件。阅读计算机手册以了解如何操作。这可能是Del键、F2键或其他键。

另一种方法是使用mokutil禁用安全启动。

自Ubuntu内核构建4.4.0-21.37以来,可以通过运行以下命令来修复此问题:

sudo apt install mokutil
sudo mokutil --disable-validation

需要创建一个密码。密码应至少为8个字符长。重启后,UEFI将询问您是否要更改安全设置。选择“是”。

然后,您将被要求输入先前创建的密码。一些UEFI固件不要求输入完整密码,而是要求输入其中的某些字符,如第1个、第3个等等。请小心。有些人不理解这一点。我也没有在第一次尝试时理解它;-)

更新:现在所有支持的Ubuntu内核中都启用了此内核配置。Ubuntu 16.04、15.10和14.04受到影响。


这对我没用。@Sputnik的回答有用。但是,我还是想知道为什么mokutil要求我输入密码以及何时需要它? - Alwin Kesler
9@AlwinKesler 在重启之前,它会要求输入密码,并在验证通过后才会对MOK数据库进行实际更改。如果没有这个步骤,一个恶意进程可以在MOK数据库中更改密钥,并在下次重启后生效。此外,现在平台“知道”请求更改的人是在重启后与之前同一人,因此必须通过硬件安全措施,如物理接触机器和知道引导时间系统密码。 - zwets
@Pilot6:由于一些技术问题,我仍然使用Ubuntu 14.04 LTS。非常感谢您更新答案。 - ravi
mokutil在16.04版本的Toshiba笔记本上对我无效。它运行得很好,但是在启动时安全启动仍然存在。最终,我选择了第一种选项,在启动时按下Esc键并关闭安全启动。 - kingledion
mokutil在我的Lenovo X1 Carbon gen3上运行得非常好 - 关于重新启动时密码字符的部分真是个很好的提醒! - jfacemyer
3在Ubuntu 18.04上对我有用。我一直想不明白为什么无论通过任何方式安装nvidia驱动程序都无法工作,甚至回到16.04也不行。这个方法解决了问题。浪费了太多时间。 - Nate
1我的Ubuntu系统非常卡顿。这完全没有道理,因为这是一台全新的笔记本电脑。现在我意识到CPU一直在工作,而我的显卡则一直处于闲置状态。这个链接也有帮助 - https://www.linuxbabe.com/ubuntu/install-nvidia-driver-ubuntu-18-04 - Peter Drinnan
这不是所需的修复方式。人们不应该需要重新启动。 - Graham
我双系统启动。我敢打赌,在更新过程中Windows又把安全启动重新开启了... - isaaclw
亲爱的Pilot6,你能帮我解决这个问题吗?https://askubuntu.com/questions/1332631/how-to-create-a-secure-boot-enabled-usb-flash - hamed

根据用户@zwets的建议,我在这里复制(并进行了编辑)一个答案:
自从内核版本4.4.0-20开始,强制要求在启用安全启动的情况下,不允许运行未签名的内核模块。如果您想保持安全启动并运行这些模块,那么下一步就是对这些模块进行签名。
所以让我们试一试吧。
  1. 创建签名密钥

    openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj "/CN=描述性名称/"
    
  2. 对模块进行签名

    sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der /path/to/module
    

注意1:对于单个驱动程序/模块,可能需要签署多个文件,因此/path/to/module可能需要替换为$(modinfo -n <modulename>),例如$(modinfo -n vboxdrv)

注意2:如果sign-file不可用,sudo kmodsign sha512 ./MOK.priv ./MOK.der /path/to/module是一种替代方法。

  • 注册安全启动的密钥
  • sudo mokutil --import MOK.der
    

    提供一个密码以便在重启后使用

  • 重新启动并按照指示注册MOK(机器所有者密钥)。这里有一个带有图片的示例。系统将再次重启。

  • 如果密钥已经正确注册,它将显示在 sudo mokutil --list-enrolled 下面。

    请告诉我您的模块是否可以在 Ubuntu 16.04 上以这种方式运行(我相信是在内核 4.4.0-21 上)。

    资源:详细网站Fedora 文章Ubuntu 实现模块签名。(他们一直在进行改进);-)

    附加资源:我创建了一个用于每次 virtualbox-dkms 升级并覆盖已签名模块的自己使用的 bash 脚本。查看我的GitHub 上的vboxsign

    对于安全(特别)关注的额外说明:;-)

    由于您创建的私钥(在此示例中为MOK.priv)可以被任何能够访问它的人使用,因此将其保密是一个好的做法。您可以使用chmod命令对其进行权限设置,使用gpg进行加密,或将其存储在其他更安全的地方。或者,如此评论所述,在第一步中删除选项-nodes。这将使用密码短语对密钥进行加密。

    在Ubuntu 14.10上,我尝试安装从源代码编译的broadcom驱动程序时,仍然看到“所需密钥不可用”的错误提示,尽管已经预先注册了密钥并签署了驱动程序。禁用验证可以解决该问题。 - Mark
    1这对我在VirtualBox和Ubuntu 16.04上起作用。 - YtvwlD
    1我在第三步遇到了以下错误:“此系统不支持EFI变量”。 “dmesg”中没有EFI条目(“dmesg | grep efi”没有结果)。 我还能做什么?谢谢。 - musbach
    您可以使用$(modinfo -n modulename)来替换路径。 - Shane
    1在我这里使用的是Ubuntu 18.04,无论我已经对talpa_syscallhook.ko模块进行了签名,以及同一目录下Sophos AV的所有其他模块,但insmod命令仍然显示"Required key not available"。我已成功注册了密钥,因为当我列出所有mok密钥时可以看到它。有关如何继续操作的任何想法吗? - Fran Marzoa
    1对于第二步,请注意单个驱动程序/模块可能有多个文件需要签名(因此使用 $(modinfo -n <modulename>))。 - prusswan

    你可以按照以下步骤在BIOS中禁用安全启动(UEFI):
    1. 重新启动你的计算机并进入BIOS菜单(例如,按下F2键)。 2. 查找安全启动选项并切换到传统模式。 在ASUS主板中:
    1. 进入高级模式(按下F7键)。 2. 在引导部分下找到安全启动选项。 3. 将"Windows UEFI模式"更改为"其他操作系统"。 4.保存并重新启动以应用设置(按下F10键)。

    2Secure Boot和“Legacy”是不同的设置。 - Pilot6
    但是,如果您启用的是“传统启动”而不是UEFI,那么这是否意味着Secure Boot未启用? - Supernormal
    @超常,是的,这就是我理解的。 - Sputnik
    在我看来,处理这个问题的最佳方式是 - 如果您需要能够加载第三方kmods - 是构建一个标准内核,使用您的发行版 /boot/config-* 文件作为初始的 .config。或者,重新构建发行版内核,但删除所有处理mok和内核锁定的补丁。 - RJVB
    只是为了让我的先前评论有个背景:我有理由从Debian Buster(无疑也被Ubuntu使用)构建一个最新的内核,并发现尽管已禁用安全启动,我仍然无法加载我的ZFS kmods。这一定是因为我没有使用与我的构建相对应的配置文件。或者是因为构建一个完全功能的内核所需的一切并未提供。想到我之所以转向Linux,是因为在Darwin中存在SIP混乱问题... - RJVB

    你还可以在运行shim-signed时禁用安全启动,使用sudo update-secureboot-policy命令。这个wiki页面解释了这种方法:
    • 打开终端(Ctrl + Alt + T),执行sudo update-secureboot-policy命令,然后选择是。
    • 输入一个8到16位的临时密码。(例如,12345678,我们稍后会使用这个密码)
    • 再次输入相同的密码进行确认。
    • 重新启动系统,在看到蓝屏(MOK管理)时按任意键。
    • 选择更改安全启动状态。
    • 输入在第2步中选择的密码,然后按Enter键。
    • 选择是以禁用shim-signed中的安全启动。
    • 按Enter键完成整个过程。

    你仍然可以在shim-signed中启用安全启动。只需执行

    sudo update-secureboot-policy --enable 然后按照上述步骤操作。


    如果你因为在Ubuntu上使用VMWare Workstation而来到这里,就像我一样,遇到了以下问题:

    无法打开dev vmmon:没有这个文件或目录。请确保内核模块`vmmon'存在

    我在这里找到了解决方法,Edson Junior提供了。当我尝试从官方VMWare说明中运行mokutil --import MOK.der时,我遇到了一个错误:

    所需密钥不可用

    Edson的代码为我解决了这两个错误:
    
    # I noticed when I did this and when he did it two of the builds failed
    $ sudo vmware-modconfig --console --install-all
    
    $ openssl req -new -x509 -newkey rsa:2048 -keyout VMWARE15.priv -outform DER -out VMWARE15.der -nodes -days 36500 -subj "/CN=VMWARE/"
    
    $ sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 ./VMWARE15.priv ./VMWARE15.der $(modinfo -n vmmon)
    
    $ sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 ./VMWARE15.priv ./VMWARE15.der $(modinfo -n vmnet)
    
    $ tail $(modinfo -n vmmon) | grep "Module signature appended"
    
    $ sudo mokutil --import VMWARE15.der
    
    now reboot
    
    $ reboot
    
    

    他还提到了一个YouTube视频这里