Grub2那些事 – 制作一个可同时支持BIOS和UEFI安全启动的系统

Grub2那些事 – 制作一个可同时支持BIOS和UEFI安全启动的系统我们已经学会制作BIOS启动的磁盘镜像和UEFI启动的磁盘镜像,但我们在使用ubuntu的时候不知道大家有没有注意过一下这个现象,在支持UEFI

大家好,欢迎来到IT知识分享网。

我们已经学会制作BIOS启动的磁盘镜像和UEFI启动的磁盘镜像,但我们在使用ubuntu的时候不知道大家有没有注意过一下这个现象,在支持UEFI启动的虚拟机中使用efibootmgr命令查看ubuntu系统的启动顺序

efibootmgr -v BootCurrent: 0005 Timeout: 0 seconds BootOrder: 0005,0000,0001,0002,0003,0004 Boot0000* UiApp FvVol(7cb8bdc9-f8eb-4f34-aaea-3ee4af6516a1)/FvFile(462caa21-7614-4503-836e-8ab6f) Boot0001* UEFI VBOX CD-ROM VB0-01f003f6 PciRoot(0x0)/Pci(0x1,0x1)/Ata(0,0,0)N.....YM....R,Y. Boot0002* UEFI VBOX CD-ROM VB2-0 PciRoot(0x0)/Pci(0x1,0x1)/Ata(1,0,0)N.....YM....R,Y. Boot0003* UEFI VBOX HARDDISK VBf5cb0757- PciRoot(0x0)/Pci(0xd,0x0)/Sata(0,65535,0)N.....YM....R,Y. Boot0004* EFI Internal Shell FvVol(7cb8bdc9-f8eb-4f34-aaea-3ee4af6516a1)/FvFile(7c04a583-9e3e-4f1c-ad65-e05268d0b4d1) Boot0005* ubuntu HD(1,GPT,6dee24a7-4fe0-466f-b6f8-546e2048aceb,0x800,0x)/File(\EFI\ubuntu\shimx64.efi)

通过这个命令我们知道efi会从 Boot0005 进行启动,默认的执行程序为 \EFI\ubuntu\shimx64.efi。那么 \EFI\ubuntu\shimx64.efi 是何物?如果想知道shimx64.efi文件是什么,可以参考后续文章。这个章节我们不会介绍这个内容,留在后续章节介绍,在这个章节我们将学习如何使用shim制作一个可以支持BIOS启动,也支持UEFI方式启动,同时也支持安全启动的磁盘镜像。

这里不会介绍grub的编译,我们这里直接使用《Grub2那些事 – 制作一个使用UEFI的系统》中编译说产生的文件。这里我们假设工作目录为bios-uefi

$ WORKSPACE=/opt/workspace/ $ mkdir -p bios-uefi $ cd $WORKSPACE/bios-uefi

制作秘钥文件

这里我们将创建OVMF安全启动所使用的DB,KEY,PK秘钥。使用以下脚本创建

#!/bin/bash # Copyright (c) 2015 by Roderick W. Smith # Licensed under the terms of the GPL v3 echo -n "Enter a Common Name to embed in the keys: " read NAME for n in PK KEK db do openssl genrsa -out "$n.key" 2048 openssl req -new -x509 -sha256 -subj "/CN=$NAME/" -key "$n.key" -out "$n.pem" -days 7300 openssl x509 -in "$n.pem" -inform PEM -out "$n.der" -outform DER done GUID=`python3 -c 'import uuid; print(str(uuid.uuid1()))'` echo $GUID > myGUID.txt for n in PK KEK db do sbsiglist --owner "$GUID" --type x509 --output "$n.esl" "$n.der" done for n in PK=PK KEK=PK db=KEK do sbvarsign --key "${n#*=}.key" --cert "${n#*=}.pem" --output "${n%=*}.auth" "${n%=*}" "${n%=*}.esl" done chmod 0600 *.key echo "" echo "" echo "For use with KeyTool, copy the *.auth and *.esl files to a FAT USB" echo "flash drive or to your EFI System Partition (ESP)." echo "For use with most UEFIs' built-in key managers, copy the *.cer files;" echo "but some UEFIs require the *.auth files." echo ""

将这个文件命名为mykeys.sh。

$ chmod +x mykeys.sh

然后执行这个命令

$ mkdir -p keys $ cd keys $ ./mykeys.sh Enter a Common Name to embed in the keys: Foo, Inc. Secure Boot key set Generating RSA private key, 2048 bit long modulus (2 primes) ..................+++++ .......................................................................................+++++ e is 65537 (0x010001) Generating RSA private key, 2048 bit long modulus (2 primes) ........+++++ .......................+++++ e is 65537 (0x010001) Generating RSA private key, 2048 bit long modulus (2 primes) .....................................................................................................+++++ ......................+++++ e is 65537 (0x010001) For use with KeyTool, copy the *.auth and *.esl files to a FAT USB flash drive or to your EFI System Partition (ESP). For use with most UEFIs' built-in key managers, copy the *.cer files; but some UEFIs require the *.auth files.

这些秘钥主要为OVMF所使用,我们还需要创建一个用于shim使用的秘钥

openssl genrsa -out "shim.key" 2048 openssl req -new -x509 -sha256 -subj "/CN=shim/" -key "shim.key" -out "shim.pem" -days 7300 openssl x509 -in "shim.pem" -inform PEM -out "shim.der" -outform DER

这样我们获得了PK,DB,KEK和SHIM秘钥。这些秘钥是后续安全启动所必不可少的。

SHIM编译

这个章节介绍一个新的组件编译即SHIM

$ cd $WORKSPACE $ git clone https://github.com/rhboot/shim.git $ make update $ sudo make EFI_PATH=/usr/lib VENDOR_CERT_FILE=$WORKSPACE/bios-uefi/keys/shim.der ENABLE_SBSIGN=1 ENABLE_SHIM_CERT=1 install-as-data ... Signing Unsigned original image install -d -m 0755 //usr/share//shim/15.4/x64/ install -m 0644 shimx64.efi //usr/share//shim/15.4/x64// install -m 0644 BOOTX64.CSV //usr/share//shim/15.4/x64// install -m 0644 mmx64.efi.signed //usr/share//shim/15.4/x64//mmx64.efi install -m 0644 fbx64.efi.signed //usr/share//shim/15.4/x64//fbx64.efi

这样我们获得了已经签发好的shimx64.efi,mmx64.efi和fbx64.efi,这些文件存放在//usr/share//shim/15.4/x64//目录中

创建磁盘镜像

这里为了方面,我们直接使用以下命令创建相关的磁盘镜像和分区

$ truncate --size 20G bios-uefi.img # 创建磁盘分区 $ sgdisk --clear \ --new 1::+1M --typecode=1:ef02 --change-name=1:'BIOS boot partition' \ --new 2::+100M --typecode=2:ef00 --change-name=2:'EFI System' \ --new 3::-0 --typecode=3:8300 --change-name=3:'Linux root filesystem' \ bios-uefi.img Creating new GPT entries in memory. Setting name! partNum is 0 Setting name! partNum is 1 Setting name! partNum is 2 Warning: The kernel is still using the old partition table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8) The operation has completed successfully.

使用sgdisk命令创建了3个分区,这里需要重点关注的是各种typecode,每一种typecode表示不同的分区类型

  • 第一个分区用于BIOS
  • 第二个分区用于EFI系统分区
  • 第三个分区作为根文件系统

使用gdisk查看分区的详细信息

$ gdisk -l bios-uefi.img GPT fdisk (gdisk) version 1.0.5 Partition table scan: MBR: protective BSD: not present APM: not present GPT: present Found valid GPT with protective MBR; using GPT. Disk bios-uefi.img:  sectors, 20.0 GiB Sector size (logical): 512 bytes Disk identifier (GUID): 812C7F89-1AFC-4E66-9923-DF32 Partition table holds up to 128 entries Main partition table begins at sector 2 and ends at sector 33 First usable sector is 34, last usable sector is  Partitions will be aligned on 2048-sector boundaries Total free space is 2014 sectors (1007.0 KiB) Number Start (sector) End (sector) Size Code Name 1 2048 4095 1024.0 KiB EF02 BIOS boot partition 2 4096  100.0 MiB EF00 EFI System 3   19.9 GiB 8300 Linux root filesystem

做好分区后,我们将相关的分区进行格式化

# 使用回环设备 $ LOOPDEV=$(losetup --find --show bios-uefi.img) $ sudo partprobe ${LOOPDEV} # 创建文件系统 $ sudo mkfs.fat -F32 ${LOOPDEV}p2 $ sudo mkfs.ext4 -F -L "root" ${LOOPDEV}p3 # 这里我们使用了root作为标签 mke2fs 1.45.5 (07-Jan-2020) Discarding device blocks: done Creating filesystem with  4k blocks and  inodes Filesystem UUID: 197e687e-b9b1-4d5b-8ff2-87e635d08801 Superblock backups stored on blocks: 32768, 98304, , , , , , , ,  Allocating group tables: done Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done

使用以上步骤,格式化EFI系统分区和root文件系统分区。

首先将rootfs.tar解压到系统的第三个分区中,将第三个分区作为根文件系统

$ MOUNTDIR=$(mktemp -d -t workXXXXXX) $ mount ${LOOPDEV}p3 $MOUNTDIR $ sudo tar -C $MOUNTDIR -xf $WORKSPACE/buildroot/output/images/rootfs.tar

安装支持BIOS启动

我们使用以下命令将grub安装到磁盘的第一个扇区,注意的是在GPT系统分区的磁盘中,第一个扇区叫做PMBR。由于其前446个字节没有使用,我们这里完全可以将GRUB安装到这个位置。

$ sudo /opt/workspace/grub-bios/sbin/grub-install --boot-directory=/mnt/boot --modules="part_msdos" ${LOOPDEV}

安装好后,我们做一下清理工作

$ sudo umount $MOUNTDIR

到这里,我们将获得一个支持bios启动的系统盘,由于还没有把内核镜像放进去,所以还不能正常启动

$ qemu-system-x86_64 -m 512 -drive file=./bios-uefi.img,format=raw -m 512

系统将正常启动。

安装支持安全启动的UEFI

下面我们将安装支持UEFI安全启动的系统盘,我们希望无论打开安全启动或者没有打开系统都能够正常启动。让我们开始我们的工作吧。

创建EFI的基本目录结构,并且将shim相关的文件拷贝到当前目录中

$ MOUNTDIR=$(mktemp -d -t workXXXXXX) # 加载系统的第二个EFI系统分区 $ mount ${LOOPDEV}p2 $MOUNTDIR $ mkdir -p EFI/BOOT $ mkdir -p EFI/test $ cp //usr/share//shim/15.4/x64//* .

然后,使用shim秘钥对shimx64.efi程序进行签发

$ sbsign --key keys/db.key --cert keys/db.pem --output shimx64.efi.signed shimx64.efi warning: data remaining[ vs ]: gaps between PE/COFF sections? warning: data remaining[ vs ]: gaps between PE/COFF sections? Signing Unsigned original image

签发grub镜像,对于比较新的Grub版本,这里需要注意的是这里需要提供一个sbat文件

$ cat <<SBATCFG > sbat.csv sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md shim,1,UEFI shim,shim,1,https://github.com/rhboot/shim SBATCFG $ $WORKSPACE/grub-efi/bin/grub-mkimage \ -d /usr/lib/grub/x86_64-efi \ -o ./grubx64.efi \ -p /EFI/test \ --sbat sbat.csv \ -O x86_64-efi \ fat iso9660 part_gpt part_msdos normal boot linux configfile loopback chain efifwsetup efi_gop \ efi_uga ls search search_label search_fs_uuid search_fs_file gfxterm gfxterm_background \ gfxterm_menu test all_video loadenv exfat ext2 ntfs btrfs hfsplus udf $ sbsign --key keys/shim.key --cert keys/shim.pem --output grubx64.efi.signed grubx64.efi Signing Unsigned original image

我们这里使用了grub-mkimage命令创建grubx64.efi程序,这里需要注意几个选项

  • -O 指示目标架构
  • -p 告诉创建目录的前缀,这里我们使用了一个叫做test的测试系统,所以这里指定的目录为/EFI/test,你也可以指定其他目录
  • –sbat sbat文件,在下一个章节我们将详细的介绍这个文件

此时,我们使用DB秘钥签发了SHIM,使用shim秘钥签发了grub。在Ubuntu发行版本中一般通过微软进行签发SHIM,使用Canonical签发其他文件。

接着,我们将制作一个支持安全启动的OVMF固件,这里我们使用了在《Grub2那些事 – 制作一个使用UEFI的系统》制作的OVMF程序。

$ cp $WORKSPACE/tianocore/edk2/Build/OvmfX64/DEBUG_GCC5/FV/OVMF_CODE.fd \ $WORKSPACE/tianocore/edk2/Build/OvmfX64/DEBUG_GCC5/FV/OVMF_VARS.fd \ $WORKSPACE/tianocore/edk2/Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd .. $ cp keys/db.der keys/KEK.der keys/PK.der hda-contents/

将OVMF相关编译的文件拷贝到当前目录,并且将DB,KER,PK的证书文件放到hda-contents目录中,这个目录我们用于将证书导入到OVMF中。

$ qemu-system-x86_64 -L . \ -drive if=pflash,format=raw,readonly,file=OVMF_CODE.fd \ -drive if=pflash,format=raw,file=OVMF_VARS.fd \ -drive file=fat:rw:hda-contents,media=disk,format=raw \ -net none

启动qemu后,接着我们将相关的证书导入到OVMF固件中。在UEFI中有一个很重要的概念即变量,UEFI根据存储在闪存中的变量来决定执行。所以操作UEFI的变量其实是直接操作闪存中的存储信息。我们运行支持UEFI的qemu模拟器后。将进入一下界面

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

等待几秒钟,或者直接按其他任何按键,系统将进入 UEFI Shell。进入命令行界面后,我们输入 exit 。可以直接进入UEFI的图形配置界面。依次进入 “Device Manager”→”Secure Boot Configuration”→ “Secure Boot Mode” ,选择 Custom Mode

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

选择出现的“Custome Secure Boot Options”,我们将进入相关秘钥导入的界面

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

下面将以PK秘钥的导入为例,说明如何当如PK秘钥导入UEFI中。选择 “PK Options”,进入PK的导入界面

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

选择“Enroll PK”

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

选择“Enroll PK Using File”

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

选择对应的文件,这里选择“PK.der”

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

最后将文件提交到UEFI固件中

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

然后分别导入DB,PKE秘钥,退出到”Secure Boot Configuration”界面中,在这个界面中我们可以明确的看到安全启动项已经被打开了

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

继续退出到主界面,选择“Continue”

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

最后执行Enter键重启,我们就可以得到一个支持安全启动的UEFI固件

Grub2那些事 - 制作一个可同时支持BIOS和UEFI安全启动的系统

细心一点会发现,OVMF_CODE.fd这个文件没有变化,变化的是OVMF_VARS.fd文件,这个文件存储了UEFI中的变量项。在真实的计算机中,很多硬件商存放的是微软的DB,KEK证书,以及自己的PK证书。而在OVMF中默认没有这些信息,所以这里我们创建了自己的PK,DB,KEK秘钥。

回归正传,由于我们在编译shim的过程中让其自动签发了mmx64和fbx64所以,这里我们不需要签发了,但需要注意是shim的mok秘钥管理器中其实存放的是两个证书,一个是其自动生成的用于签发mmx64和fbx64的证书,还有一个是我们导入的shim证书。

将 shimx64.efi.signed,grubx64.efi.signed,mmx64.efi,fbx64.efi放到正确的位置

$ install -m 0644 shimx64.efi.signed EFI/test/shimx64.efi $ install -m 0644 shimx64.efi.signed EFI/BOOT/BOOTX64.efi $ install -m 0644 grubx64.efi.signed EFI/test/grubx64.efi $ install -m 0644 mmx64.efi EFI/test/mmx64.efi $ install -m 0644 mmx64.efi EFI/BOOT/mmx64.efi $ install -m 0644 fbx64.efi EFI/BOOT/fbx64.efi

然后,我们根据UEFI的配置创建一个BOOTX64.CSV文件,UEFI会默认通过这个文件找到正确的启动选项。

$ echo "shimx64.efi,test,,This is the boot entry for Test" | iconv -t UCS-2LE >BOOTX64.CSV $ install -m 0644 BOOTX64.CSV EFI/test/BOOTX64.CSV

到这里,和安全启动相关的配置基本已经完成,接着我们还需要配置grub的配置文件。

$ sudo blkid ${LOOPDEV}p3 /dev/loop1p3: LABEL="root" UUID="197e687e-b9b1-4d5b-8ff2-87e635d08801" TYPE="ext4" PARTLABEL="Linux root filesystem" PARTUUID="7e844aef-eb31-433c-9ae0-7330e17f601b" cat <<GRUBCFG > grub.cfg search.fs_uuid 197e687e-b9b1-4d5b-8ff2-87e635d08801 root hd0,gpt3 set prefix=(\$root)'/boot/grub' configfile \$prefix/grub.cfg GRUBCFG $ cp grub.cfg EFI/test/

读过之前文章的对这段估计这样陌生了,我们使用blkid找到第三个分区的UUID,作为grub的默认根文件系统。让grub从第三个分区找真实的grub配置文件,这个配置文件就是一个桥接的过程。

$ MOUNTDIR=$(mktemp -d -t workXXXXXX) $ sudo mount /dev/loop1p3 $MOUNTDIR $ cp $linux_kernl/arch/x86_64/boot/bzImage . sbsign --key keys/shim.key --cert keys/shim.pem --output bzImage.signed bzImage $ cp bzImage.signed $MOUNTDIR/boot/bzImage

使用以上命令签发了linux内核镜像,在UEFI安全启动中,使用SHIM机制,需要将grub和内核,以及内核模块都要经过shim秘钥的签发。所以这里使用shim秘钥签发内核镜像,并将内核镜像拷贝到了第三个分区的/boot目录中。同时还需要更改第三个分区的grub.cfg配置文件,这个配置文件位于 /boot/grub/grub.cfg 中。将文件修改为以下内容。

set default="0" set timeout="5" menuentry "Buildroot" { set root='hd0,gpt3' linux /boot/bzImage root=/dev/sda3 rootwait console=tty1 }

这个磁盘镜像使用了3个分区,第一个用于bios,其实没用,第二个用于uefi系统分区,第三个用于根文件系统,所以这里设置了第三个分区作为根文件系统。

将第三个分区卸载

$ sudo umount $MOUNTDIR

接着,我们将第二个分区挂在到系统中,并且将制作的EFI文件拷贝到这个分区中。

sudo mount ${LOOPDEV}p2 $MOUNTDIR sudo cp -R EFI $MOUNTDIR

至此,我们完成了UEFI安全系统的磁盘镜像。

验证

使用以下命令,支持UEFI安全启动的uefi磁盘能够启动成功

$ sudo qemu-system-x86_64 \ -drive if=pflash,format=raw,readonly,file=./OVMF_CODE.fd \ -drive if=pflash,format=raw,file=./OVMF_VARS.fd \ -drive file=./bios-uefi.img,format=raw -m 512 \ -net none -serial file:serial.log

使用以下命令验证关闭UEFI安全启动的这个磁盘能否启动成功,OVMF.fd这个文件直接从编译的结果获取,没有打开安全启动

$ sudo qemu-system-x86_64 \ -bios OVMF.fd \ -drive file=./bios-uefi.img,format=raw -m 512 \ -net none -serial file:serial.log

使用以下命令验证bios方式的这个磁盘能否启动成功

$ sudo qemu-system-x86_64 \ -drive file=./bios-uefi.img,format=raw -m 512

正常情况下,以上3三种情况都可以正常启动。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/50412.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信