openSUSE:UEFI

跳转至: 导航, 搜索

关于 UEFI

UEFI 标准介绍

UEFI(统一可扩展固件接口)是一个新的工业标准,指定了一台计算机必须在预引导环境提供的不同接口。UEFI 将在开机后和操作系统完全加载时控制计算机。UEFI 也负责提供介于计算机提供的资源和操作系统间的接口。

换句话说,在此 UEFI 用于替代和扩展旧式的 BIOS 固件。

UEFI 不是一个新鲜事物。从 1990 年代中期 Intel 就在研发 EFI / UEFI,像 HP 或 Apple 这样的制造商也很早就提供了 EFI 机器。但是当微软发布 Windows 8 后使得它成为引导新的受认证计算机的必需途径。

UEFI 规格 (http://www.uefi.org/specs/) 是一个包含全部接口、变量、固件生产商必须提供的结构、以及可供操作系统访问的结构的大文档。好消息是 Linux 从 2000 年起就可使用 GRUB 或 elilo 在引导时使用 EFI 了。事实上 openSUSE 12.2 就支持了 UEFI,最新的 openSUSE 12.3 也对 Secure Boot 扩展实现了实验性支持。

是的,扩展。Secure boot 是 UEFI 的一个扩展。UEFI 的一个核心点就是它是可扩展的。UEFI 有一个内部的虚拟机,该虚拟机独立于它运行的架构。该标准接受为此虚拟机编译的特定二进制文件(EFI 执行文件),并在此环境中执行。这些执行文件可以是设备驱动、应用程序或 UEFI 标准的扩展。UEFI,在某种意义上说,像是计算机启动时运行的一个小型操作系统,该操作系统的主要任务是查找并加载另一个主力操作系统。

我怎么才能知道我有一台 UEFI 计算机呢?通常我们应该在开机阶段按 F1(或 ESC,根据计算机而变)检查固件配置。浏览菜单,我们将会查明计算机是运行在 legacy 模式(老式的 BIOS 模式),EFI 模式还是混合模式,混合模式是说将基于我们要加载的操作系统选择实际使用的模式。

若您的计算机没有 UEFI 支持,但是您想要使用 openSUSE 测试此项新技术,您可以使用 QEMU 和 Intel 的 UEFI 参考实现:使用 QEMU 了解 UEFI 和 Secure Boot

GPT

UEFI 改动的不止有固件、syscall 和接口。它也提议了一种新的硬盘分区风格。GUID 分区表 (GPT) 在此将替代老式的主引导记录 (MBR) 方案。

MBR 有一些重要的限制,比如主分区和逻辑分区的数量,和这些分区的大小等。GPT 解决了这些问题,现在我们可以使用任意数量的分区 (in sets of 128),可寻址的磁盘空间也达到了 2^64 比特 (这里我们使用艾克萨字节)。因此,如果我们有大硬盘的话,这种分区方式正式我们所要的。另一个核心区憋局势 GPT 使用一个独一无二的 UUID 数引用每个分区,避免了分区标识符间的撞车。

若 YaST2 检测到了我们正处于 EFI 模式,在全新安装时它将尝试为我们创建一个 GPT 分区方案。一旦创建好了 GPT 分区,我们就不再能够使用老式的 fdisk 来创建,移除或编辑分区了。能这么做的新工具叫 gdisk,位于 gptfdisk 软件包中。用法和 fdisk 工具的一样。

有时,如果我们计划测试和体验一下不同的模式,我们可能想要从硬盘移除 GPT 格式。我们可以使用 YaST2 做到。去专家分区器选项,选择正确的磁盘,并在 "专家..." 按钮下选择 "创建新分区表"

这将根据我们正在运行的系统替换分区表。

EFI 系统分区

EFI 系统分区(ESP)是 UEFI 期望找到可用于引导全部安装在设备上的操作系统的 EFI 程序的分区。同时,EFI 也将在这里查找一些引导时所用的设备驱动,以及其它需要在操作系统引导前运行的工具。

此分区使用 FAT 文件系统,可通过 YaST2 在全新安装时创建出来,双重引导时也可使用别的系统创建好的。这意味着若我们在计算机上已经安装了一个 Windows,YaST2 将能检测到 EFI 分区,并将会把用于加载 openSUSE 的新 EFI 引导加载器放在里面,并且在 /boot/efi 挂载点下挂载该分区。

默认情况下,固件将搜索 /EFI/BOOT/bootx64.efi 作为要加载的扩展,并执行之以加载操作系统。在 Windows 机器上,正确的扩展是在 /EFI/Microsoft/Boot/BCD.efi,而 openSUSE 是 /EFI/opensuse/grubx64.efi(或者是 shim.efi 若您启用了 Secure Boot)

引导管理器

为了选择正确的加载操作系统的扩展,EFI 为用户提供了一个内部引导管理器。操作系统负责为它自己创建新引导项,我们可在通电过程启用引导管理器,并列出全部引导项,通常是按 F9 或 F12。但我们也可以使用 efibootmgr 工具查询和编辑这些引导项。例如,要列出当前引导项我们可以运行 efibootmgr -v

在上面的快照中我们可以看到 openSUSE 创建了两个用于引导的不同的引导项。一个用于安全模式,一个用于正常开机。

若出于某种原因我们丢失了一个引导项,我们可以使用 efibootmgr 重新创建之。例如,要重新创建 'opensuse' 项我们可以这样:

$ efibootmgr -c -L “openSUSE-alt” -l '\EFI\opensuse\grubx64.efi'

EFI 变量

UEFI 标准指定了一系列存储于固件不会丢失的部分中的变量。这些变量用于存储信息和控制 UEFI 系统行为。例如,当我们在引导管理器中创建了一个新引导项时,或者我们启用或禁用了 Secure Boot 选项时,我们其实是在访问和修改这些变量中的某个的值。

我们可以通过 Sysfs 从 openSUSE 中直接查询和访问这些变量。Sysfs 是一个内核提供的虚拟文件系统,用来将某些内部信息导出到用户空间。我们可以在 '/sys/firmware/efi/vars/' 中找到这些变量。因此,例如,可以这样查询最后一个引导加载器引导项:

$ hexdump -C /sys/firmware/efi/vars/Boot0007-*/data

Secure Boot

背景

UEFI Secure Boot 是一种限制哪些二进制程序可被执行来引导系统的手段。固件只能执行携带了众所周知的操作系统实体的加密签名的引导加载器。在 Secure boot 环境中使用 X.509 证书来识别这些操作系统实体。

目前多数默认启用了 Secure Boot 的消费 PC 硬件都预装了 Microsoft Windows 8。因此固件只认为 Microsoft 才是「众所周知的操作系统实体」,只有它才能签名引导加载器。为了能够引导 openSUSE 而不去重新配置已知签名签发人列表或关闭 Secure Boot,openSUSE 的引导加载器必须携带一个 Microsoft 的签名。

openSUSE 12.3 中的实现

openSUSE 12.3 在 UEFI 系统上默认使用的引导加载器是 grub2。在 Secure Boot 模式下,也会使用一个额外的叫做 'shim' 的引导加载器。在该模式下不会直接调用 grub2,而是先让固件加载 'shim'。'shim' 携带了一个 Microsft 的签名以让固件认出我们。之后 'shim' 去认出签名 grub2 所用的 openSUSE 证书。然后 grub2 就能加载也由 openSUSE 证书签名的内核了。加载内核后 ,Secure Boot 环节就结束了。openSUSE 所用的 Linux 内核并没有施加其它额外的蛋疼限制。

为了允许自定义引导加载器和内核,shim 提供了一种导入自定义签名的方法。实现该目的要用到 'MokManager' 程序。当指示 'shim' 加载一个未由「众所周知的操作系统实体」签名的二进制程序时,它会调用 MokManager,后者允许将证书导入到已知签名签发人数据库中。

如何启用或禁用 Secure Boot 支持

openSUSE 12.3 中的 Secure Boot 支持仍被我们认为是实验性的。安装程序 YaST 无法自动检测出是否启用了 Secure Boot。在安装期间它会提供一个手动启用 Secure Boot 支持的选项。开启那个选项就会安装 shim。要在一个安装好的系统中开启或禁用 Secure Boot 支持可使用 YaST 引导加载器模块。

如何确定计算机是否开机了 Secure Boot

要确认计算机是否在固件中启用了 Secure Boot,请在一个 Linux 壳层中以 root 身份输入以下命令:

 od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data

若命令输出未 '1' 则 Secure Boot 就是启用的。现在已经知道某些固件版本是不能用的,即使 Secure Boot 是启用的它们在这儿也会显示 '0'。最好去 BIOS 里瞧瞧。

引导一个自制内核

Secure boot 不会阻止您使用您自行编译的内核。您只需要用您自己的证书签名它,并让证书为固件或 MOK 所知即可。

创建一个用于签名的自制 X.509 密钥和证书

 openssl req -new -x509 -newkey rsa:2048 -keyout key.asc -out cert.pem -nodes -days 666 -subj "/CN=$USER/"

将密钥和证书封装为 PKCS#12 结构

 openssl pkcs12 -export -inkey key.asc -in cert.pem -name kernel_cert -out cert.p12

生成预签名所用的 NSS 数据库

 certutil -d . -N

将 PKCS#12 中包含的密钥和证书导入进 NSS 数据库

 pk12util -d . -i cert.p12

以新签名「加持」内核

 pesign -n . -c kernel_cert -i arch/x86/boot/bzImage -o vmlinuz.signed -s

列出内核映像上的签名

 pesign -n . -S -i vmlinuz.signed

这样您就能够像往常一样将内核安装到 /boot 了。因为内核现在有了一个自定义签名,所以用于签名的证书需要被导入进固件或 MOK 中。

将证书转换为 DER 格式以导入到 UEFI 固件或 MOK

 openssl x509 -in cert.pem -outform der -out cert.cer

将证书复制进 EFI 系统分区以方便访问

 sudo cp cert.cer /boot/efi/

不幸的是 openSUSE 12.3 下 mokutil 仍未编译成功,因此没有一种舒服的方法来自动启动 MOK。以下步骤描述了如何手动启动 MOK。

  • 重新引导
  • 在 grub 菜单按 'c' 键
  • 输入(假设 EFI 系统分区是 'hd0' 磁盘上的 'gpt1' 分区)
 chainloader (hd0,gpt1)/EFI/opensuse/MokManager.efi
 boot
  • 选择 "从磁盘注册密钥"
  • 导航到 cert.der 文件并按回车
  • 遵循指示注册密钥。通常这应该是按 '0' 然后按 'y' 确认

另外固件菜单可能也提供了添加新证书到 'db' 的方法。

不使用厂商提供的密钥引导计算机

若固件菜单提供了重置 Secure Boot 所用密钥的选项,您可能可以安装新 PK, KEK 和 db 而不用 Microsoft 的密钥。要这样的话请将 /usr/lib64/efi/shim-opensuse.der 导入到 db 以让 openSUSE 内核能够引导。默认的 shim 是由 Microsfot 和 openSUSE 双方都签了名的。但是某些固件版本可能不支持双重签名。在那种情况下可以安装 /usr/lib64/efi/shim-opensuse.efi,它是只由 openSUSE 签名的,其它跟 /boot/efi/EFI/opensuse/shim.efi 的内容一样。

启动只支持一个供应商签名的机器

有些固件无法解析 EFI 映像中的多个签名,在这种情况下,使用默认的 shim 会启动失败。如果固件菜单没有提供安装新密钥的选项,则必须手动删除 openSUSE 的签名以解决问题。

1. 安装 mozilla-nss-tools 和 pesign
zypper install mozilla-nss-tools pesign
2. 创建一个临时的 nss 数据库
mkdir certdb
certutil -N -d certdb
(按 “Enter” 忽略密码请求)
3. 去掉 openSUSE 签名
pesign -n certdb/ -r -i /usr/lib64/efi/shim.efi -o shim.efi -u 1
4. 用新生成的 shim.efi 替换默认的 shim.efi
mv shim.efi /boot/efi/EFI/opensuse/shim.efi
5. 删除临时 nss 数据库
rm -rf certdb


每次更新 shim 后都必须重复这些步骤。 这种类型的固件应该越来越少了,因为多签名支持已经包含在 edk2 的上游一年多,但仍然可能在较旧的机器中遇到。

术语表

PK
"平台密钥" 典型地是指由硬件制造商安装在计算机上的证书。需要一个有效的 PK 签名才能够修改 KEK。
KEK
更新签名数据库需要一个 "密钥交换密钥" 的有效签名。
db
包含了已知证书、签名或二进制程序的哈希值的签名数据库。只有能通过该数据库验证的二进制程序才可以被固件执行。更新签名数据库需要一个有效的 KEK 签名。
dbx
签名数据库黑名单是 'db' 的暗面,基本上就是证书、签名和哈希值的黑名单。若二进制程序匹配到了其中任何一条那它都无法执行。更新签名数据库黑名单需要一个有效的 KEK 签名。
MOK
机器所有者密钥。MokManager 所用的一个额外的证书或哈希值数据库。用户可使用 MokManager 在引导时交互地更新 MOK。