Linux x86_64 UEFI 启动

文章目录

  • 前言
  • 一、UEFI
  • 二、Disk device compatibility
    • 2.1 GPT 磁盘分区表
      • 2.1.1 简介
      • 2.1.2 Linux
    • 2.2 ESP(EFI) 文件系统
      • 2.2.1 简介
      • 2.2.2 Linux
        • Linux Kernel EFI Boot Stub
  • 三、UEFI + GPT + grub2
    • 3.1 简介
    • 3.2 引导方式
  • 3.3 BOOTX64.EFI
    • 3.4 shimx64.efi
    • 3.5 grubx64.efi
  • 四、安全启动
    • 4.1 简介
    • 4.2 Linux
  • 参考资料

前言

本文以 centos 7 (3.10.0 ),x86_64平台为例。

固件保存在主板上的 ROM 中,是计算机上电后执行的第一段程序。固件启动阶段的核心功能包括硬件初始化、硬件自检和加载 bootloader,最终会把控制权转交给给 bootloader。
固件启动阶段主要有两种启动方式:Legacy BIOS 和 UEFI。

Linux系统是使用UEFI还是BIOS启动,查看/sys/firmware/efi是否存在:

# ls /sys/firmware/efi
config_table  efivars  esrt  fw_platform_size  fw_vendor  runtime  runtime-map  systab  vars

一、UEFI

Unified Extensible Firmware Interface(UEFI)统一可扩展固件接口是一种规范,定义了用于启动计算机硬件的平台固件的架构,以及其与操作系统进行交互的接口。
在这里插入图片描述

UEFI取代了BIOS,后者存在于所有兼容IBM PC的个人计算机的引导ROM中,尽管它可以通过CSM引导提供与BIOS的向后兼容性。
与其前身BIOS相反,BIOS最初由IBM作为专有软件创建的事实上的标准,UEFI是由一个行业联盟维护的开放标准。

由EFI规范定义的接口包括包含平台信息的数据表,以及可供操作系统加载程序和操作系统使用的引导和运行时服务。UEFI固件相对于BIOS提供了几个技术优势:
(1)能够引导包含大容量分区(超过2 TB)的磁盘,使用GUID分区表(GPT - GUID Partition Table)进行分区。
(2)灵活的预操作系统环境,包括网络功能、图形用户界面(GUI)和多语言支持。
(3)支持32位(例如IA-32、ARM32)或64位(例如x64、AArch64)的预操作系统环境。
(4)使用C语言进行编程。
(5)使用Python解释器进行UEFI Shell的Python编程。
(6)模块化设计,允许固件和驱动程序的灵活组合和替换。
(7)向后和向前的兼容性,可以与旧版本的EFI固件和新版本的UEFI固件兼容。
(8)安全性:BIOS不包含内置的安全措施,例如安全启动(Secure Boot)。EFI支持安全启动,可以防止未经授权的操作系统或恶意软件篡改启动过程。

二、Disk device compatibility

2.1 GPT 磁盘分区表

2.1.1 简介

除了使用主引导记录(MBR)的标准PC磁盘分区方案外,UEFI还与GUID分区表(GPT)分区方案配合使用,GPT分区方案摆脱了MBR的许多限制。特别是,MBR对磁盘分区数量和大小的限制(每个磁盘最多四个主分区,每个磁盘最大容量为2 TB,即2 × 240字节)得到放宽。更具体地说,GPT允许最大磁盘和分区大小达到8 ZiB(8 × 270字节)。

GPT分区方案相比MBR具有更大的灵活性和扩展性,可以支持更大容量的磁盘和更多的分区。它还提供了更好的数据完整性和可靠性,支持磁盘自我修复和冗余存储。因此,在使用UEFI的系统中,可以利用GPT分区方案来充分利用大容量磁盘和更多的分区布局选项。

GUID Partition Table(GPT)是一种用于物理计算机存储设备(如硬盘驱动器或固态硬盘)分区表布局的标准,它使用全局唯一标识符(UUID)或全局唯一标识符(GUID)来标识分区。作为统一可扩展固件接口(UEFI)标准的一部分(作为PC BIOS的替代方案由统一EFI论坛提议),GPT也被一些BIOS使用,这是由于主引导记录(MBR)分区表的限制,MBR分区表使用32位用于传统512字节磁盘扇区的逻辑块寻址(LBA)。

所有现代个人计算机操作系统都支持GPT。其中一些,包括基于x86架构的macOS和微软Windows,仅支持在具有EFI固件的系统上从GPT分区引导,但FreeBSD和大多数Linux发行版可以在具有BIOS或EFI固件接口的系统上从GPT分区引导。

如下图所示:
在这里插入图片描述
与MBR类似,GPT使用逻辑块寻址(LBA)代替历史上的柱面-磁头-扇区(CHS)寻址。保护性MBR存储在LBA 0处,GPT头部存储在LBA 1处,并在最后一个LBA处备份GPT头部。GPT头部包含对分区表(分区项数组)的指针,通常位于LBA 2处。每个分区表上的条目大小为128字节。UEFI规范规定,无论扇区大小如何,分区项数组都分配了至少16,384字节的空间。因此,在具有512字节扇区的磁盘上,至少使用32个扇区用于分区项数组,而第一个可用块位于LBA 34或更高位置;而在具有4,096字节扇区的磁盘上,至少使用4个扇区用于分区项数组,而第一个可用块位于LBA 6或更高位置。

2.1.2 Linux

在Linux中启用对GPT的支持需要在内核配置期间打开CONFIG_EFI_PARTITION选项(EFI GUID分区支持)。此选项允许Linux在系统固件将系统控制权交给Linux后,识别和使用GPT磁盘。

# cat /boot/config-3.10.0-693.el7.x86_64 | grep CONFIG_EFI_PARTITION
CONFIG_EFI_PARTITION=y

为了向后兼容,Linux可以在基于BIOS的系统中使用GPT磁盘进行数据存储和引导,因为GRUB 2和Linux都支持GPT。这样的设置通常被称为BIOS-GPT。由于GPT包含保护性MBR,基于BIOS的计算机可以使用存储在保护性MBR引导代码区域中的GPT感知引导加载程序从GPT磁盘引导。对于GRUB而言,这样的配置需要一个BIOS引导分区,以便GRUB嵌入其二级代码,因为GPT分区磁盘中不存在MBR之后的空隙(该空隙被GPT的主头和主分区表占用)。这个分区通常为1 MB大小,在GPT方案中,该分区的全局唯一标识符(GUID)为21686148-6449-6E6F-744E-656564454649,仅在BIOS-GPT设置中由GRUB使用。从GRUB的角度来看,在MBR分区方案中不存在这种分区类型。如果系统是基于UEFI的,则不需要此分区,因为在这种情况下不需要嵌入第二阶段代码。

UEFI系统可以访问GPT磁盘并直接从中引导,这允许Linux使用UEFI引导方法。在UEFI系统上从GPT磁盘引导Linux涉及创建EFI系统分区(ESP),其中包含UEFI应用程序,如引导加载程序、操作系统内核和实用工具。这样的设置通常被称为UEFI-GPT,建议ESP的大小至少为512 MB,并且使用FAT32文件系统进行格式化以实现最大的兼容性。

为了向后兼容,一些UEFI实现还通过兼容性支持模块(CSM)支持从MBR分区的磁盘引导,该模块提供了传统BIOS兼容性。在这种情况下,在UEFI系统上引导Linux与在传统基于BIOS的系统上引导相同。

2.2 ESP(EFI) 文件系统

2.2.1 简介

EFI(可扩展固件接口)系统分区或ESP是存储设备(通常是硬盘驱动器或固态硬盘)上的一个分区,用于具有统一可扩展固件接口(UEFI)的计算机。当计算机启动时,UEFI固件加载存储在ESP上的文件以启动操作系统和各种实用程序。

ESP包含已安装操作系统的引导加载程序、引导管理器或内核映像(通常包含在其他分区中),用于在启动时由固件使用的硬件设备的设备驱动程序文件,旨在在引导操作系统之前运行的系统实用程序,以及数据文件,如错误日志。

EFI系统分区使用基于FAT文件系统的文件系统进行格式化,其规范基于UEFI规范并作为其一部分进行维护;因此,文件系统规范独立于原始的FAT规范。在GUID分区表(GPT)方案中,EFI系统分区的全局唯一标识符(GUID)是C12A7328-F81F-11D2-BA4B-00A0C93EC93B,而在主引导记录(MBR)分区表方案中,其标识符为0xEF。无论是GPT还是MBR分区的磁盘都可以包含EFI系统分区,因为UEFI固件需要支持这两种分区方案。此外,还支持用于CD-ROM和DVD的El Torito引导格式。

UEFI通过将分区的第一个块(扇区)保留为兼容性代码来提供与传统系统的向后兼容性,实际上创建了一个传统的引导扇区。在传统基于BIOS的系统中,将分区的第一个扇区加载到内存中,并将执行权转移到该代码上。UEFI固件不会执行MBR中的代码,除非通过兼容性支持模块(CSM)以传统BIOS模式引导。

UEFI规范要求完全支持MBR分区表。然而,某些UEFI实现在检测到引导磁盘上的某些类型的分区表时立即切换到基于BIOS的CSM引导,从而有效地阻止了从包含在MBR分区磁盘上的EFI系统分区进行UEFI引导。

UEFI固件支持从可移动存储设备(如USB闪存驱动器)引导。为此,可移动设备使用FAT12、FAT16或FAT32文件系统进行格式化,同时需要根据标准ESP文件层次结构存储引导加载程序,或者通过向系统的引导管理器提供引导加载程序的完整路径。另一方面,固定驱动器上始终期望FAT32文件系统。

2.2.2 Linux

GRUB 2、elilo和systemd-boot是传统的、功能齐全的独立UEFI引导管理器(也称为引导加载管理器),用于Linux。一旦被UEFI固件加载,它们可以访问和引导来自它们所支持的所有设备、分区和文件系统的内核映像,而不仅限于EFI系统分区。

EFI系统分区的挂载点取决于所使用的引导加载器。较旧的引导加载器如GRUB 2和lilo/elilo默认为/boot/efi。或者,systemd-boot更喜欢/efi或/boot而不是/boot/efi,这是因为嵌套的autofs挂载可能导致潜在的复杂问题。无论挂载点路径如何,其内容在Linux引导后是可访问的。

对于GRUB2:

 tree /boot/efi/
/boot/efi/
└── EFI
    ├── BOOT
    │   ├── BOOTX64.EFI
    │   ├── fallback.efi
    │   └── fbx64.efi
    └── centos
        ├── BOOT.CSV
        ├── BOOTX64.CSV
        ├── fonts
        │   └── unicode.pf2
        ├── fw
        ├── fwupia32.efi
        ├── fwupx64.efi
        ├── grub.cfg
        ├── grubenv
        ├── grubx64.efi
        ├── mmx64.efi
        ├── MokManager.efi
        ├── shim.efi
        ├── shimx64-centos.efi
        └── shimx64.efi
Linux Kernel EFI Boot Stub

EFI Boot Stub使得在不使用传统UEFI引导加载器的情况下,可以引导Linux内核映像。通过伪装成PE/COFF可执行映像,并对固件呈现为UEFI应用程序,启用EFI Boot Stub的Linux内核映像可以直接由UEFI固件加载和执行。这样的内核映像仍然可以由基于BIOS的引导加载器加载和运行;因此,EFI Boot Stub允许单个内核映像在任何引导环境中工作。

Linux内核对EFI Boot Stub的支持通过在内核配置中打开CONFIG_EFI_STUB(EFI stub支持)选项来启用。它被合并到Linux内核主线版本的3.3版中,于2012年3月18日发布。

# cat /boot/config-3.10.0-693.el7.x86_64 | grep CONFIG_EFI_STUB
CONFIG_EFI_STUB=y

Systemd-boot是一个简单的UEFI引导管理器,它加载和运行配置的EFI映像,仅访问EFI系统分区。配置文件片段、内核映像和initrd映像需要驻留在EFI系统分区上,因为systemd-boot不提供访问其他分区或文件系统上的文件的支持。Linux内核需要使用CONFIG_EFI_STUB=y进行构建,以便可以直接作为UEFI映像执行。

通过EFI Stub,Linux内核可以被直接被编译成UEFI的app,可以直接被UEFI固件识别和启动,完全不需要借助第三方bootloader了。

在x86和ARM平台上,内核的zImage/bzImage可以伪装成PE/COFF映像,从而使EFI固件加载程序将其作为EFI可执行文件加载。修改bzImage头部的代码以及固件加载程序跳转到的EFI特定入口点共同被称为"EFI boot stub",它们分别位于arch/x86/boot/header.S和drivers/firmware/efi/libstub/x86-stub.c。对于ARM架构,EFI stub实现在arch/arm/boot/compressed/efi-header.S和drivers/firmware/efi/libstub/arm32-stub.c中。在不同架构之间共享的EFI stub代码位于drivers/firmware/efi/libstub目录下。

对于arm64架构,没有压缩内核的支持,因此Image本身伪装成PE/COFF映像,并且EFI stub链接到内核中。arm64的EFI stub位于drivers/firmware/efi/libstub/arm64.c和drivers/firmware/efi/libstub/arm64-stub.c中。

通过使用EFI boot stub,可以在没有传统EFI引导加载程序(如grub或elilo)的情况下引导Linux内核。由于EFI boot stub执行了引导加载程序的任务,在某种意义上它就是引导加载程序。

启用EFI boot stub需要使用CONFIG_EFI_STUB内核选项。

请参考:
https://www.kernel.org/doc/html/latest/admin-guide/efi-stub.html
https://zhuanlan.zhihu.com/p/28708585

三、UEFI + GPT + grub2

3.1 简介

bootloader 启动阶段的核心功能是加载内核和 initramfs,并将控制权交给内核。

Centos7 的 bootloader 为 GRUB 2,根据启动方式的不同,可分成两种引导方式:BIOS+MBR/GPT+grub2 和 UEFI+GPT+grub2。

从GPT分区磁盘引导UEFI系统通常被称为UEFI-GPT引导。

这里主要描述UEFI+GPT+grub2引导方式。

这种引导方式,固件 UEFI 从 ESP 分区文件系统下读取 bootloader。Centos ESP 分区文件系统采用 vfat,其目录结构如下:

# tree /boot/efi/EFI/
/boot/efi/EFI/
├── BOOT
│   ├── BOOTX64.EFI
│   ├── fallback.efi
│   └── fbx64.efi
└── centos
    ├── BOOT.CSV
    ├── BOOTX64.CSV
    ├── fonts
    │   └── unicode.pf2
    ├── fw
    ├── fwupia32.efi
    ├── fwupx64.efi
    ├── grub.cfg
    ├── grubenv
    ├── grubx64.efi
    ├── mmx64.efi
    ├── MokManager.efi
    ├── shim.efi
    ├── shimx64-centos.efi
    └── shimx64.efi

与传统的PC BIOS不同,UEFI不依赖于引导扇区,而是在UEFI规范中定义了一个引导管理器。当计算机启动时,引导管理器会检查引导配置,并根据其设置执行指定的操作系统引导加载程序或操作系统内核(通常是引导加载程序)。引导配置由存储在NVRAM中的变量定义,包括指示操作系统加载程序或操作系统内核的文件系统路径的变量。

UEFI可以自动检测操作系统引导加载程序,这使得从可移动设备(如USB闪存驱动器)进行简单的引导成为可能。这种自动检测依赖于标准化的操作系统引导加载程序的文件路径,路径的格式取决于计算机架构。例如,在x86-64系统上,操作系统加载程序的文件路径为 /boot/efi/EFI/BOOT/BOOTX64.EFI,而在ARM64架构上为/boot/efi/EFI/BOOT/BOOTAA64.EFI。

# file /boot/efi/EFI/BOOT/BOOTX64.EFI
/boot/efi/EFI/BOOT/BOOTX64.EFI: PE32+ executable (EFI application) x86-64 (stripped to external PDB), for MS Windows
# file /boot/efi/EFI/BOOT/BOOTAA64.EFI
/boot/efi/EFI/BOOT/BOOTAA64.EFI: PE32+ executable (EFI application) Aarch64 (stripped to external PDB), for MS Windows

3.2 引导方式

# tree /boot/efi/EFI/
/boot/efi/EFI/
├── BOOT
│   ├── BOOTX64.EFI
│   ├── fallback.efi
│   └── fbx64.efi
└── centos
    ├── BOOT.CSV
    ├── BOOTX64.CSV
    ├── fonts
    │   └── unicode.pf2
    ├── fw
    ├── fwupia32.efi
    ├── fwupx64.efi
    ├── grub.cfg
    ├── grubenv
    ├── grubx64.efi
    ├── mmx64.efi
    ├── MokManager.efi
    ├── shim.efi
    ├── shimx64-centos.efi
    └── shimx64.efi

引导方式如下:

x86_64: uefi ==> shimx64.efi ==> grubx64.efi ==> /boot/efi/EFI/centos/grub.cfg ==> vmlinuz & initramfs

x86 架构系统中,shimx64.efi 和 grubx64.efi 是 UEFI 启动方式下的 bootloader,他们以文件的形式存在于磁盘的 /boot/efi/EFI/centos 目录下,UEFI 可以直接识别文件系统,并获取 shimx64.efi 加载到内存运行,然后 shimx64.efi 获取 grubx64.efi,grubx64.efi 则通过 grub.cfg 寻找 vmlinuz 和 initfamfs,并将其加载到内存中。

Centos 中 BOOTX64.EFI 是 shimx64.efi 的复制。第一次启动时,固件中无引导条目,默认会加载 ESP 分区下 EFI/BOOT/BOOTX64.EFI,BOOTX64.EFI 加载 fbx64.efi,fbx64.efi 根据 EFI/centos/BOOTX64.CSV 文件向固件注册引导项 Centos,并将引导程序指向 /EFI/centos/shimx64.efi,跳转到 shimx64.efi,shimx64.efi最终会加载 grubx64.efi,grubx64.efi根据 grub.cfg 读取并加载内核和 initramfs,并将控制权交给内核。 从第二次启动开始,因为固件中已注册了 Centos引导项,所以直接从 shimx64.efi 启动。

首次启动:

UEFI --> BOOTX64.EFI --> fbx64.efi --> shimx64.efi --> grubx64.efi --> grub.cfg --> vmlinuz & initramfs

非首次启动:

UEFI --> shimx64.efi --> grubx64.efi --> grub.cfg --> vmlinuz & initramfs

shim 的作用主要是安全启动,grubx64.efi 完成实际的引导。

在大多数Linux发行版中,用于UEFI启动的引导加载程序通常是shim.efi或者grubx64.efi。shim.efi是一个轻量级的引导加载程序,主要用于支持安全启动(Secure Boot)功能,并随后加载grubx64.efi(GRUB2),GRUB2是更为复杂的引导加载器,它可以加载Linux内核和初始化RAM磁盘(initrd/initramfs),进而启动操作系统。

3.3 BOOTX64.EFI

BOOTX64.EFI 是一个通用的引导加载程序文件,具有较高的权限,并可以在各种环境下启动计算机。无论计算机是否安装了操作系统,如果存在 BOOTX64.EFI 文件,UEFI 固件将使用它作为默认的引导加载程序。

BOOTX64.EFI 具有广泛的应用场景,可以用于各种目的,包括维护、安装计算机系统以及启动不同的操作系统。通过使用 BOOTX64.EFI,您可以进入各种模式,如 EFI Shell、ISO、Windows、Linux 等,从而在不同的环境下启动计算机。

BOOTX64.EFI 是一种UEFI引导加载程序文件,用于在64位x86架构的计算机上启动操作系统。它是与UEFI固件兼容的引导加载程序,负责加载操作系统内核并引导系统启动。

在UEFI系统中,BOOTX64.EFI通常被用作默认的引导加载程序。当计算机启动时,UEFI固件会查找并执行BOOTX64.EFI文件,从而启动操作系统。

BOOTX64.EFI通常与特定的操作系统或引导管理器相关联。例如,在Windows系统中,UEFI固件会加载BOOTX64.EFI来引导Windows操作系统。类似地,在某些Linux发行版中,UEFI固件也会加载BOOTX64.EFI来引导该发行版的内核和引导程序。

需要注意的是,BOOTX64.EFI的文件名可能因操作系统和计算机制造商而有所不同。不同的操作系统和引导环境可能使用不同的文件名来执行相同的功能。例如,某些Linux发行版可能使用grubx64.efi或shimx64.efi作为默认的引导加载程序文件。

BOOTX64.EFI文件是UEFI系统的启动管理器,它会在计算机启动时被加载到内存中,然后启动操作系统的安装程序或引导管理器。这个文件通常位于Linux ISO image的EFI目录下,它可以被用来启动UEFI系统安装程序或启动其他操作系统的引导管理器。

总结来说,BOOTX64.EFI是一种UEFI引导加载程序文件,用于在64位x86计算机上启动操作系统。它是与UEFI固件兼容的引导加载程序,负责加载操作系统内核并引导系统启动。具体的文件名可能因操作系统和计算机制造商而有所不同。

3.4 shimx64.efi

shimx64.efi 是一个用于 UEFI Secure Boot 的特殊引导加载程序。它在 Linux 系统中的 BOOT 阶段用于启动操作系统,并提供了 UEFI Secure Boot 的支持。

在启用 UEFI Secure Boot 的系统中,引导加载程序必须具有受信任的数字签名才能被固件信任并加载。然而,某些 Linux 发行版的引导加载程序(如 GRUB)可能没有预先被签名,因而无法通过 Secure Boot 的验证。

为了解决这个问题,UEFI 固件允许使用一个称为 “shim” 的中间引导加载程序。shimx64.efi 就是 shim 的一个典型实现,适用于 x86-64 架构的系统。

shimx64.efi 本身是由 UEFI 固件预先信任的,因此可以通过 Secure Boot 的验证。它的主要作用是加载并启动 GRUB 或其他 Linux 发行版的引导加载程序。由于 shimx64.efi 是经过签名并可信任的,它可以作为信任链的一部分,允许其他未签名的引导加载程序或内核模块被加载,并确保系统的启动过程是安全的。

因此,当使用 UEFI Secure Boot 启动 Linux 系统时,shimx64.efi 是作为引导加载程序使用的,它负责加载并启动其他组件,如 GRUB 或操作系统内核,以确保在启动过程中的安全性和完整性。

3.5 grubx64.efi

(1)
grubx64.efi 是 GRUB 引导加载程序的一个文件,用于在 UEFI 系统中启动操作系统。它是 GRUB 的 UEFI 版本,专门设计用于 x86-64 架构的计算机。

grubx64.efi是GNU GRUB引导管理器的UEFI版本,它是一种常用的引导程序,被广泛应用于Linux系统中。当计算机使用UEFI启动时,UEFI固件会查找EFI目录下的grubx64.efi文件,并将其加载到内存中。然后,grubx64.efi将会显示一个菜单,列出可用的操作系统和内核,允许用户选择要启动的操作系统或内核。在Linux ISO image中,grubx64.efi文件通常被用作引导管理器,用于启动Linux操作系统的安装程序。

在 UEFI 系统中,grubx64.efi 被用作主引导加载程序,负责加载操作系统内核和初始化 RAM 文件系统(initramfs)。它是由 GRUB 提供的一个可信的引导加载程序,通常与 shimx64.efi 结合使用,以支持 UEFI Secure Boot。

grubx64.efi 的配置文件通常位于 /boot/grub/grub.cfg 或 /etc/grub.d/ 目录中。在配置文件中,可以定义引导菜单,包括可供选择的操作系统、启动参数和其他设置。

GRUB 具有强大的功能和灵活性,可以处理多个操作系统的引导和配置。它支持多个文件系统,可以通过配置文件进行自定义和扩展。通过编辑和配置 grubx64.efi 的配置文件,可以修改引导菜单、添加新的启动选项、设置默认启动项等。

对于Linux发行版,grubx64.efi是GRUB2在UEFI环境下的引导加载程序。虽然Grub是开源软件,理论上可以编译和定制,但通常情况下,个人用户不是通过直接编辑.efi文件来配置GRUB,而是通过编辑其配置文件(如/boot/grub/grub.cfg)来更改引导菜单、内核选项等。如果确实需要修改源代码,那也是先修改源代码然后重新编译生成新的.efi文件。

总结来说,grubx64.efi 是 GRUB 引导加载程序的 UEFI 版本,用于在 UEFI 系统中启动操作系统。它与 shimx64.efi 结合使用,提供了强大的引导和配置功能,使用户能够灵活地管理和启动多个操作系统。

(2)
grubx64.efi文件是怎么找到grub.cfg文件的:

在UEFI系统中,grubx64.efi引导管理器启动后,它会搜索EFI系统分区中的特定目录和文件,以找到grub.cfg配置文件。具体来说,grubx64.efi通常会按照以下顺序搜索grub.cfg文件:

首先,grubx64.efi会在EFI目录下搜索grub.cfg文件。如果在EFI目录下找到了grub.cfg文件,它会直接加载并执行该文件。

如果在EFI目录下没有找到grub.cfg文件,grubx64.efi会继续搜索EFI目录下的/boot/grub目录。在该目录下,它会尝试查找grub.cfg文件,并加载执行该文件。

如果在/boot/grub目录下也没有找到grub.cfg文件,grubx64.efi会继续搜索EFI系统分区中的其他目录,包括/efi/{distro}/、/efi/boot/等,以查找grub.cfg文件。

一旦grubx64.efi找到了grub.cfg文件,它就会将文件加载到内存中,并根据文件中的配置信息启动相应的操作系统或内核。注意,grub.cfg文件的位置和名称可能因Linux发行版和安装方式而有所不同,但通常情况下,它们会遵循上述搜索规则。

四、安全启动

UEFI Secure Boot(UEFI 安全引导)是一种验证机制,用于确保固件启动的代码是可信的。

正确、安全地使用 UEFI Secure Boot 需要对每个在引导时加载的二进制文件进行验证,验证过程是通过与固件中的已知密钥进行比对。这些密钥标识了可信的供应商和二进制文件的来源,或者通过加密哈希算法识别的特定可信二进制文件。

大多数 x86 硬件出厂时都预装了微软的密钥。这意味着我们通常可以依赖这些系统中的固件信任由微软签名的二进制文件,而 Linux 社区在很大程度上依赖这个假设来实现 Secure Boot。例如,Red Hat 和 SUSE 也采用了相同的流程。

许多 ARM 和其他架构也支持 UEFI Secure Boot,但可能没有在固件中预装密钥。在这些架构上,可能需要使用由硬件所有者加载到固件中的证书重新签名引导映像。

4.1 简介

Secure Boot(安全启动)是一项在UEFI(统一可扩展固件接口)标准中的安全功能,旨在为预引导过程添加一层保护。它通过维护一个加密签名的二进制文件列表来验证引导时运行的程序是否经过授权或禁止,从而提高机器核心引导组件(引导管理器、内核、initramfs)未被篡改的可信度。

简单来说,所谓安全启动,就是主板厂商在 UEFI 的 ROM 中内置了一个公钥,操作系统发行方用对应的私钥,去给系统的内核,或者引导器签名。这样,系统启动的时候,UEFI 会用 ROM 中内置的对应公钥,去验证这个内核,或者引导器是否为发行方提供的。如果是,那么验证通过,可以正常启动;如果不是,那么启动就会被终止。

私钥签名,公钥验证。

UEFI规范定义了一种称为Secure Boot的协议(BIOS不具备这样的内置安全机制),可以通过阻止加载未使用可接受数字签名签名的UEFI驱动程序或操作系统引导加载程序来保护引导过程。并未指定驱动程序的签名具体的机械细节。当启用Secure Boot时,它最初处于“设置”模式,允许将称为“平台密钥”(PK)的公钥写入固件。一旦密钥被写入,Secure Boot进入“用户”模式,只有使用平台密钥签名的UEFI驱动程序和操作系统引导加载程序才能被固件加载。可以将其他证书添加到存储在内存中的数据库中的“密钥交换密钥”(KEK)中,以允许使用其他证书,但它们仍然必须与平台密钥的私有部分有关联。Secure Boot也可以设置为“自定义”模式,在该模式下可以向系统中添加不与私钥匹配的其他公钥。

在2011年,微软宣布获得其Windows 8操作系统认证的计算机必须预装微软的公钥并启用Secure Boot。随后,该公司被批评者和自由软件/开源倡导者(包括自由软件基金会)指责试图利用UEFI的Secure Boot功能阻碍或完全阻止安装诸如Linux等替代操作系统。微软否认Secure Boot要求旨在形成闭环,并通过明确规定,获得Windows 8认证的基于x86架构的系统必须允许Secure Boot进入自定义模式或被禁用,但在使用ARM架构的系统上不允许。Windows 10允许OEM厂商决定用户是否可以管理其x86系统的Secure Boot。

其他开发人员对在Linux系统中实现Secure Boot的法律和实际问题提出了担忧。前红帽开发人员Matthew Garrett指出,GNU通用公共许可证第3版的条款可能会阻止在未向发行版的开发人员披露私钥的情况下使用GNU GRand Unified Bootloader(不过,自由软件基金会已经澄清了其立场,保证提供密钥的责任由硬件制造商承担),而对于启用了Secure Boot的高级用户来说,构建能够正常工作的自定义内核而不进行自签名也是困难的。其他开发人员建议提供带有另一个密钥的已签名的Linux版本,但指出说服OEM厂商随同微软密钥一起提供所需密钥将会很困难。

几个主要的Linux发行版已经针对Secure Boot开发了不同的实现方式。Garrett本人开发了一个称为shim的最小化引导加载程序,它是一个预编译、已签名的引导加载程序,允许用户单独信任Linux发行版提供的密钥。Ubuntu 12.10使用一个较旧版本的shim,预先配置为使用Canonical自己的密钥,仅验证引导加载程序并允许加载未签名的内核。开发人员认为仅签名引导加载程序的做法更可行,因为一个可信任的内核只能保护用户空间,而不能保护Secure Boot旨在增加保护的预引导状态。这也允许用户构建自己的内核并使用自定义内核模块,而无需重新配置系统。Canonical还维护自己的私钥,用于签名预装在运行该操作系统的经过认证的OEM计算机上的Ubuntu安装,并且还计划强制执行Secure Boot要求,即需要在固件中包含Canonical密钥和微软密钥(出于兼容性原因)。Fedora也使用shim,但要求内核及其模块也必须签名。

关于操作系统内核及其模块是否必须签名存在争议;虽然UEFI规范并没有要求,但微软声称他们的合同要求如此,并保留撤销用于签署可能用于破坏系统安全性的代码的任何证书的权利。在Windows中,如果启用了Secure Boot,所有内核驱动程序必须经过数字签名;非WHQL驱动程序可能会被拒绝加载。2013年2月,另一位红帽开发人员试图提交一个补丁给Linux内核,使其能够解析由微软签2011年,微软宣布获得其Windows 8操作系统认证的计算机必须预装微软的公钥并启用Secure Boot功能。这一举措引起了批评者和自由软件/开源倡导者(包括自由软件基金会)的指责,称微软试图利用UEFI的Secure Boot功能限制或完全阻止安装其他操作系统(如Linux)。微软否认Secure Boot要求旨在形成闭环,并明确规定获得Windows 8认证的基于x86架构的系统必须允许Secure Boot进入自定义模式或禁用,但使用ARM架构的系统则不受此限制。Windows 10允许OEM厂商决定用户是否可以管理其x86系统的Secure Boot。

关于在Linux系统中实现Secure Boot的法律和实际问题引起了其他开发人员的关注。前红帽开发人员Matthew Garrett指出,GNU通用公共许可证第3版的条款可能会阻止在未向发行版开发人员披露私钥的情况下使用GNU GRand Unified Bootloader。不过,自由软件基金会已经澄清了其立场,确保提供密钥的责任由硬件制造商承担。对于启用了Secure Boot的高级用户来说,构建能够与Secure Boot启用一起使用的自定义内核而无需自签名也是困难的。其他开发人员提议提供带有另一个密钥的已签名Linux版本,但指出说服OEM厂商将所需密钥与微软密钥一起提供可能很困难。

许多主要的Linux发行版现在都支持UEFI Secure Boot,例如RHEL(RHEL 7及更高版本)、CentOS(CentOS 7及更高版本)、Ubuntu、Fedora、Debian(Debian 10及更高版本)、OpenSUSE和SUSE Linux。这些发行版采用了不同的Secure Boot实现方式,例如使用shim引导加载程序、签名引导加载程序和内核,以及允许自定义内核等。

4.2 Linux

mokutil 命令用于管理机主密钥(MOK),这些密钥由 shim 层用于验证 grub2和内核映像,也可用于验证安全启动是否启用。

验证安全启动是否启用:

# mokutil --sb-state
or
# bootctl

查看当前所有已注册的密钥:

# mokutil --list-enrolled

在Ubuntu上,除了initrd映像之外,所有预计作为引导过程的一部分加载的预构建二进制文件都由Canonical的UEFI证书签名。Canonical的UEFI证书被嵌入在由微软签名的shim加载程序中,因此本身隐式地受到信任。

在没有预加载来自微软的签名证书的架构或系统上,用户可以替换shim或grub上的现有签名,并根据其自己在系统固件中导入的证书进行验证。

系统引导时,固件根据固件BootEntry变量加载shim二进制文件。Ubuntu在安装时安装自己的BootEntry,并且在每次更新GRUB引导加载程序时可能会更新它。由于shim二进制文件由微软签名,因此在与固件中已存在的证书进行验证时,它被固件验证和接受。由于shim二进制文件嵌入了Canonical的证书以及自己的信任数据库,因此引导环境的其他元素除了被预加载在固件中的可接受证书之一签名外,还可以使用Canonical的UEFI密钥签名。

shim加载完成后,接下来加载的是第二阶段映像。这可以是两种情况之一:如果系统正常启动,则加载GRUB;如果需要进行密钥管理任务,则加载MokManager,这是由固件变量配置的(通常在之前运行系统时更改)。

如果正常引导,GRUB二进制文件(grub*.efi)将被加载,并尝试根据所有先前已知的受信任来源进行验证。Ubuntu的GRUB二进制文件由Canonical的UEFI密钥签名,因此成功通过验证,引导过程继续进行。

如果引导以执行密钥管理任务,将加载MokManager二进制文件(mm*.efi)。通过由shim签名的临时密钥对MokManager二进制文件进行了明确的信任。这意味着只有与特定shim二进制文件一起构建的MokManager二进制文件才被允许运行,并且限制了使用受损工具的可能性。MokManager允许在系统控制台上的任何用户注册密钥、删除受信任的密钥、注册二进制哈希并在shim级别切换Secure Boot验证,但大多数任务需要输入先前设置的密码以确认控制台上的用户确实是请求更改的人。这些密码只在单次shim/MokManager运行期间保留,并在完成或取消过程后立即清除。完成密钥管理后,系统将重新启动,而不仅仅继续引导,因为可能需要密钥管理更改才能成功完成引导。

一旦系统继续引导到GRUB,GRUB过程将加载任何所需的配置(通常从ESP(EFI系统分区)加载配置,指向根分区或引导分区上的另一个配置文件),该配置将指向要加载的内核映像。

到目前为止,EFI应用程序完全可以访问系统固件,包括访问更改受信任固件变量的权限,因此要加载的内核也必须根据信任数据库进行验证。官方的Ubuntu内核由Canonical的UEFI密钥签名,因此它们成功通过验证,并将控制权移交给内核。initrd映像不会被验证。

对于非官方内核或用户构建的内核,如果用户希望在保留UEFI Secure Boot的全部功能的同时加载这些内核,还需要采取额外的步骤。当启用UEFI Secure Boot时,所有内核都必须经过签名才能被GRUB加载,因此用户需要进行签名。或者,用户可以在启用官方内核的情况下,通过使用’sudo mokutil --disable-validation’命令并在提示输入密码时提供密码,禁用shim中的验证,并重新启动;或者在固件中完全禁用Secure Boot。

到目前为止,任何验证要加载的映像失败都会导致关键错误,停止引导过程。系统不会继续引导,并且如果其他BootEntry变量可能包含有效和受信任的引导路径,可能会在一段时间后自动重新启动。

加载并验证的内核将禁用固件的Boot Services,从而降低权限并有效地切换到用户模式,其中对受信任变量的访问仅限于只读。鉴于内核模块的广泛权限,任何没有内核内置的模块在加载时也需要进行验证。由Canonical与官方内核一起构建和提供的模块由Canonical的UEFI密钥签名,因此受信任。用户自定义构建的模块需要用户在加载模块之前采取必要的步骤对模块进行签名。可以使用’kmodsign’命令来实现这一点。

未经签名的模块将被内核拒绝。使用insmod或modprobe尝试插入它们将失败并显示错误消息。

鉴于许多用户需要第三方模块才能使其系统正常工作或使某些设备正常运行,并且这些第三方模块需要在系统上进行本地构建以适应运行的内核,Ubuntu提供了工具化来自动化和简化签名过程。

参考资料

https://en.wikipedia.org/wiki/UEFI
https://www.intel.com/content/www/us/en/developer/articles/tool/unified-extensible-firmware-interface.html

https://mp.weixin.qq.com/s/N_lSjtorg0Ho_hSBiM5uKA
https://blog.csdn.net/u013434525/article/details/136433642
https://blog.csdn.net/Anhui_Chen/article/details/106988113
https://www.cnblogs.com/shamoguzhou/p/17380191.html
https://blog.csdn.net/hawava/article/details/116232981
https://www.cnblogs.com/liuzhenbo/p/10825136.html

https://www.freebuf.com/news/261563.html
https://wiki.ubuntu.com/UEFI/SecureBoot
https://www.zhihu.com/question/392260941
https://zhuanlan.zhihu.com/p/36370829
https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/637620.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

4.双指针+递归

一、双指针编程技巧 方法参数传递数组 将数组通过方法参数传递,方法操作的数组和main方法中的数组指向同一块内存区域,意味着方法操作数组,同时会引起main方法中数组的改变以引用的方式作为方法参数进行传递的 元素交换 定义临时变量temp&a…

代码随想录算法训练营第16天 |● 104.二叉树的最大深度 559.n叉树的最大深度 ● 111.二叉树的最小深度 ● 222.完全二叉树的节点个数

文章目录 前言104.二叉树的最大深度思路知识点 方法一 递归法方法二 迭代法 559. n叉树的最大深度111.二叉树的最小深度思路方法一 后向遍历递归法方法二 迭代法 222.完全二叉树的节点个数思路方法一 当成普通二叉树来做方法二 利用完全二叉树的特性 总结 前言 所有的题目一刷…

带你玩转OpenHarmony AI:打造智能语音子系统

简介 AI时代,智者当先,判断一个终端设备是否智能,语音能力是必不可缺的。智能家居、智慧厨房、智能汽车等等,一切衣食住行都在往智能方向发展,那我们该如何在OpenAtom OpenHarmony(简称“OpenHarmony”&am…

MySQL进阶 日志结尾以及8.0新特性

日志结尾 前面我们聊了mysql的undo日志,redo日志,binlog等等,也从一条update语句来分析了一下日志的执行思路以及版本控制是怎么回事,四大特性是怎么实现的等等 今天我们来说说最后一个错误日志 其实用处不大 因为对我们开发人员来说基本上是没有权限来查看错误日志的 一般…

c++读取文本文件出现乱码问题

else if (type 2) { //教师身份验证 int fId; //从文件中获取的id号 string fName; //从文件中获取的姓名 string fPwd; //从文件中获取的密码 while (ifs >> fId && ifs >> fName && ifs >> fPwd) { cout…

windows Oracle 11g服务器端和客户端安装 SQLark连接ORACLE

1 从ORACLE官网下载数据库安装包 https://edelivery.oracle.com/osdc/faces/SoftwareDelivery 2:安装数据库 注意:在加载组件的这一步,如果你的电脑里面有杀毒软件,首先把安装目录加入白名单,要不然可能会一直加载组件失败。…

面向对象的理解

1.结构化程序设计(面向过程) 结构化程序主张按功能来分析系统需求,结构化的主要原则: 自顶向下 逐步求精 模块化设计 结构化程序会按功能把程序分为一个个的单独的文件,例如:让灯亮这个功能,就会由多个函数构成一…

银行总部文件自动下发,如何保证不影响专线网络使用?

银行在我国金融体系中占据重要地位,是我国市场经济的重要组成部分。我国商业银行随着自身不断发展,规模日益扩大,形成了“总行-分行-支行-营业网点”的典型层级管理模式。在日常中,银行总部存在文件下发的场景: 银行总…

c4d云渲染是工程文件会暴露吗?

在数字创意产业飞速发展的今天,C4D云渲染因其高效便捷而备受欢迎。然而,随着技术应用的深入,人们开始关注一个核心问题:在享受云渲染带来的便利的同时,C4D工程文件安全吗?是否会有暴露的风险?下…

常见的字符编码

字符:各种文字和符号的总称,包括各个国家的文字,标点符号,图形符号,数字等 字符集:字符集是多个符号的集合,每个字符集包含的字符个数不同 字符编码:字符集只是规定了有哪些字符&a…

openlayers绘制经纬网格,有添加或者移除功能

项目需要在地图中添加经纬网格,然后看了一下官网有相关的介绍 官网 我的项目是vue写的,当点击多选框显示隐藏经纬网格,下面直接写代码 这是绘制经纬网格方法 //引入 import TileArcGISRest from ol/source/TileArcGISRest import "ol/o…

k近邻和kd树

K近邻 选取k值的时候可以采用交叉验证的方法 一般采用欧氏距离 kd树 采用树这个特殊的数据结构来实现k近邻算法 先假设是二维的情况 下面讲解kd树的完整构造过程 找这个中位数是按照每棵子树来创建的 前提是已经有了一棵kd树,然后来一个实例点

Ai编码的助手,现在我用这个

给你分享一个AI编码助手—百度Comate! https://comate.baidu.com/zh/shopping?inviteCodeaz5z518a 记得在你的vscode 或 jetbrains编码工具里体验体验哦

Python UDP编程简单实例

TCP是建立可靠的连接,并且通信双方都可以以流的形式发送数据。 相对于TCP,UDP则是面向无连接的协议,不需要建立连接,只需要知道对方IP地址和端口号,就可以直接发送数据包。但是只管发送不保证到达。 虽然UDP传输数据…

新定义RD8T36P48点亮LED--汇编

其实汇编和C语言差不多,简单的东西用汇编挺好,中等及以上复杂度的程序还是C语言更灵活 直接在keil新建好工程,选好芯片型号和下载方式,再创建一个.asm文件并添加到工程, 工程创建完如图 工程配置 代码 ORG 0000HL…

U-Mail邮件系统取得多项适配认证,全面支持国产化信创环境

随着信息技术的发展,信息化建设越来越深入到社会各个领域,成为驱动经济社会发展的重要力量。在此背景下,我国正加快构建国家信息安全保障体系,实现自主可控,形成安全可靠的信息技术体系。这正是我们所说的“信创”&…

【计算机网络原理】浅谈应用层协议的自定义和传输层UDP协议的总结

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

重磅推荐!四信AI智能一体屏系列全网上线

近年来,随着物联网、云计算、人工智能等新兴技术快速发展,制造、能源、交通、零售、医疗等行业设备需要更高程度的自动化控制。 传统的计算机和控制设备早已无法满足如今高性能复杂任务的要求,越来越多主流行业的项目落地依靠工控机&#xff…

CCF20221201——现值计算

CCF20221201——现值计算 代码如下&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n,a[1001];float i,sum0.0;scanf("%d %f",&n,&i);for(int j0;j<n1;j){scanf("%d",&a[j]);suma[j]*pow((1i),-j);}print…

抽烟行为检测:从传统巡查到智能算法

在当前人工智能和计算机视觉技术的迅猛发展下&#xff0c;基于视觉分析的抽烟行为检测算法成为一种高效的技术手段。此类算法通常依赖于深度学习模型&#xff0c;特别是卷积神经网络&#xff08;CNN&#xff09;&#xff0c;通过对摄像头捕捉的视频流进行实时分析&#xff0c;能…