[PATCH v4 0/3] Add EFI Boot Guard bootloader package & example recipe

0 views
Skip to first unread message

Christopher Obbard

unread,
Jun 17, 2026, 9:23:43 PM (4 days ago) Jun 17
to buil...@buildroot.org, James Hilliard, Thomas Petazzoni, Yegor Yefremov, efibootg...@googlegroups.com, Christopher Obbard
This patch series adds support for the EFI Boot Guard bootloader
(https://github.com/siemens/efibootguard) to Buildroot. EFI Boot Guard
can be useful when designing systems using A/B slot-based upgrades.

The first patch introduces the EFI Boot Guard bootloader package which
builds the EFI application as well as userspace and host applications.

The second patch adds a host-only package, osslsigncode, which is used
for signing the EFI binaries in the example EFI Boot Guard recipe
(introduced in the next patch).

The third patch adds an example recipe which demonstrates how to use
EFI Boot Guard in a typical EFI A/B boot scenario. This may serve as a
reference for users looking to integrate EFI Boot Guard into their
system. The introduced readme.txt file documents the example recipe.

A later patch series will extend the example recipe with integration
between EFI Boot Guard and RAUC, but that is still pending on RAUC
upstream [0].

EFI Boot Guard also provides a tool for generating UKI images, which
can then be signed for Secure Boot. The example recipe includes
instructions on how to generate a certificate chain, sign the image
and test Secure Boot in QEMU with OVMF firmware.

The example recipe has been boot-tested on QEMU with OVMF firmware and
I have confirmed the image boots & runs as expected.

Feedback welcome!

[0] https://github.com/rauc/rauc/pull/1450

Signed-off-by: Christopher Obbard <obb...@gmail.com>
---
Changes in v4:
- Rebase onto latest master Buildroot branch.
- Patch 1 - "boot/efibootguard: new boot package":
- Add EFIBOOTGUARD_CPE_ID_VENDOR.
- Use BR2_PACKAGE_GNU_EFI_ARCH_SUPPORTS instead of a local architecture
support symbol and remove the unused x86-64 only option.
- Depend on a glibc toolchain with wchar support and add a Config.in
comment for unsupported toolchains.
- Always select BR2_PACKAGE_PCIUTILS since EFI Boot Guard links against
libpci.
- Add host-pkgconf to target and host dependencies and host-python3 to
host dependencies (for bg_gen_unified_kernel).
- Use the full --include argument in AUTORECONF_OPTS instead of -I.
- Update user visible references from efibootguard to EFI Boot Guard.
- Install EFI Boot Guard and kernel-stub EFI binaries for all supported
architectures.
- Install EFI binaries directly to BINARIES_DIR instead of an
efibootguard subdirectory.
- Add the Debian patch to drop ld --fatal-warnings to fix issue building
on armhf.
- Do not install bg_gen_unified_kernel into the target filesystem as it
is mainly useful at image/UKI assembly time.
- Remove the stale TODO about the Debian stack-protector patch.
- Patch 2 - "package/osslsigncode: add host package":
- Newly package required to sign EFI binaries in example recipe.
- Patch 3 - "board/pc-efibootguard: add example EFI Boot Guard recipe":
- Generate the ESP, EFI Boot Guard slot configuration and boot slot
contents from post-image.sh instead of post-build.sh.
- Drop unused genimage.cfg UUID templating.
- Replace README.md with Buildroot-style readme.txt and expand the
documentation for image layout, QEMU usage, slot configuration,
watchdog handling, UKI boot and Secure Boot testing.
- Remove the QEMU helper script and document the QEMU command directly
in the readme.
- Enable EFI Boot Guard watchdog by default.
- Add optional UKI generation using bg_gen_unified_kernel (enabled by
default).
- Add optional Secure Boot signing support (enabled by default).
- Enable EFI framebuffer console support and the QEMU i6300esb watchdog
driver in the kernel fragment.
- Add a systemd watchdog configuration so Linux takes over the watchdog
after EFI Boot Guard arms it.
- Reduce the example image size by shrinking boot partitions to 32M
and rootfs partitions to 120M.
- Switch to Bootlin x86-64 glibc stable external toolchain.
- Simplify the kernel configuration by using the upstream x86_64
defconfig.
- Remove unrelated packages from the example image, including wifi
firmware, connman and acpid.
- Link to v3: https://lore.kernel.org/r/20260524-wip-obbardc-boot-efibootg...@gmail.com

Changes in v3:
- Rebase on latest master branch
- Fix shellcheck warnings in board/pc-efibootguard/post-build.sh
- Add note that UKI/Secure Boot is not enabled in the example recipe
- Convert example recipe readme.txt to Markdown
- Bring-up EFI Boot Guard tools in example recipe & document usage
- Add note about RAUC integration patch
- Link to v2: https://lore.kernel.org/r/20260419-wip-obbardc-boot-efibootg...@gmail.com

Changes in v2:
- Rebase on top of buildroot 2026.02
- Update efibootguard to v0.22
- Link to v1: https://lore.kernel.org/r/20251219-wip-obbardc-boot-efibootg...@gmail.com

---
Christopher Obbard (3):
boot/efibootguard: new boot package
package/osslsigncode: add host package
board/pc-efibootguard: add example EFI Boot Guard recipe

DEVELOPERS | 4 +
board/pc-efibootguard/genimage.cfg | 56 ++++
board/pc-efibootguard/linux.fragment | 29 +++
board/pc-efibootguard/post-image.sh | 162 ++++++++++++
board/pc-efibootguard/readme.txt | 281 +++++++++++++++++++++
.../etc/systemd/system.conf.d/10-watchdog.conf | 7 +
boot/Config.in | 2 +
.../0001-Do-not-use-ld-fatal-warnings.patch | 32 +++
boot/efibootguard/Config.in | 30 +++
boot/efibootguard/Config.in.host | 8 +
boot/efibootguard/efibootguard.hash | 3 +
boot/efibootguard/efibootguard.mk | 67 +++++
configs/pc_x86_64_efibootguard_defconfig | 24 ++
package/Config.in.host | 1 +
package/osslsigncode/Config.in.host | 9 +
package/osslsigncode/osslsigncode.hash | 3 +
package/osslsigncode/osslsigncode.mk | 21 ++
17 files changed, 739 insertions(+)
---
base-commit: 67449130e9fdd71a38ca26539dddfa8c882b1977
change-id: 20250207-wip-obbardc-boot-efibootguard-initial-pkg-9d16e4b283fd

Best regards,
--
Christopher Obbard <obb...@gmail.com>

Christopher Obbard

unread,
Jun 17, 2026, 9:23:44 PM (4 days ago) Jun 17
to buil...@buildroot.org, James Hilliard, Thomas Petazzoni, Yegor Yefremov, efibootg...@googlegroups.com, Christopher Obbard
This patch adds a new boot package to Buildroot to build the
EFI Boot Guard bootloader from the https://github.com/siemens/efibootguard
repository.

EFI Boot Guard can be chainloaded as an EFI application or used as a
standalone bootloader and can be useful when booting A/B systems.

Add a recipe to build the EFI bootloader application, user-space
tooling & host tooling (both of which are used to manage EFI Boot Guard
configuration).

Signed-off-by: Christopher Obbard <obb...@gmail.com>
---
DEVELOPERS | 1 +
boot/Config.in | 2 +
.../0001-Do-not-use-ld-fatal-warnings.patch | 32 +++++++++++
boot/efibootguard/Config.in | 30 ++++++++++
boot/efibootguard/Config.in.host | 8 +++
boot/efibootguard/efibootguard.hash | 3 +
boot/efibootguard/efibootguard.mk | 67 ++++++++++++++++++++++
7 files changed, 143 insertions(+)

diff --git a/DEVELOPERS b/DEVELOPERS
index d591c62805..1c77d02afc 100644
--- a/DEVELOPERS
+++ b/DEVELOPERS
@@ -706,6 +706,7 @@ F: package/perl-time-parsedate/
F: package/perl-x10/

N: Christopher Obbard <obb...@gmail.com>
+F: boot/efibootguard/
F: package/dtui/

N: Colin Foster <colin....@in-advantage.com>
diff --git a/boot/Config.in b/boot/Config.in
index d73d221431..8e6dc7a5cc 100644
--- a/boot/Config.in
+++ b/boot/Config.in
@@ -15,6 +15,8 @@ source "boot/barebox/Config.in"
source "boot/binaries-marvell/Config.in"
source "boot/boot-wrapper-aarch64/Config.in"
source "boot/edk2/Config.in"
+source "boot/efibootguard/Config.in"
+source "boot/efibootguard/Config.in.host"
source "boot/grub2/Config.in"
source "boot/mv-ddr-marvell/Config.in"
source "boot/mxs-bootlets/Config.in"
diff --git a/boot/efibootguard/0001-Do-not-use-ld-fatal-warnings.patch b/boot/efibootguard/0001-Do-not-use-ld-fatal-warnings.patch
new file mode 100644
index 0000000000..2970826b20
--- /dev/null
+++ b/boot/efibootguard/0001-Do-not-use-ld-fatal-warnings.patch
@@ -0,0 +1,32 @@
+Date: Tue, 7 May 2024 09:36:45 +0200
+From: Bastian Germann <ba...@debian.org>
+Subject: Do not use ld fatal-warnings
+
+fatal-warnings are almost guaranteed to break the build when using a more
+recent linker than the upstream developers. Get rid of them so the package
+can be built with some warnings and be maintained sanely in the long run.
+
+Upstream: N/A; not suitable for upstream, which intentionally relies on
+--fatal-warnings. Taken from Debian (Forwarded: not-needed):
+https://salsa.debian.org/debian/efibootguard/-/blob/master/debian/patches/Do-not-use-ld-fatal-warnings.patch
+
+Signed-off-by: Christopher Obbard <obb...@gmail.com>
+---
+ Makefile.am | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index c7aed67..b27ea87 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -293,7 +293,6 @@ efi_ldflags = \
+ -z max-page-size=4096 \
+ --warn-common \
+ --no-undefined \
+- --fatal-warnings \
+ $(LDFLAGS_NO_WARN_RWX_SEGMENTS) \
+ -L $(GNUEFI_LIB_DIR) \
+ $(GNUEFI_LIB_DIR)/crt0-efi-$(ARCH).o
+--
+2.43.0
+
diff --git a/boot/efibootguard/Config.in b/boot/efibootguard/Config.in
new file mode 100644
index 0000000000..746f0b7b70
--- /dev/null
+++ b/boot/efibootguard/Config.in
@@ -0,0 +1,30 @@
+config BR2_TARGET_EFIBOOTGUARD
+ bool "efibootguard"
+ depends on BR2_PACKAGE_GNU_EFI_ARCH_SUPPORTS
+ depends on BR2_USE_WCHAR
+ depends on BR2_TOOLCHAIN_USES_GLIBC
+ select BR2_PACKAGE_GNU_EFI
+ select BR2_PACKAGE_PCIUTILS
+ help
+ EFI Boot Guard is a UEFI bootloader intended for robust
+ A/B style updates. It arms a hardware watchdog before
+ handing over control to the OS and supports a fail-safe
+ boot mechanism to roll back if a boot attempt fails.
+
+ https://github.com/siemens/efibootguard
+
+if BR2_TARGET_EFIBOOTGUARD
+
+config BR2_TARGET_EFIBOOTGUARD_INSTALL_TOOLS
+ bool "install tools"
+ help
+ Install the EFI Boot Guard user-space tools (e.g.
+ bg_printenv and bg_setenv) on the target. These tools
+ allow reading and updating EFI Boot Guard configuration
+ in user-space.
+
+endif # BR2_TARGET_EFIBOOTGUARD
+
+comment "efibootguard needs a glibc toolchain w/ wchar"
+ depends on BR2_PACKAGE_GNU_EFI_ARCH_SUPPORTS
+ depends on !BR2_USE_WCHAR || !BR2_TOOLCHAIN_USES_GLIBC
diff --git a/boot/efibootguard/Config.in.host b/boot/efibootguard/Config.in.host
new file mode 100644
index 0000000000..c7af5c3120
--- /dev/null
+++ b/boot/efibootguard/Config.in.host
@@ -0,0 +1,8 @@
+config BR2_TARGET_HOST_EFIBOOTGUARD
+ bool "host efibootguard"
+ help
+ Build EFI Boot Guard companion tools for the host. These
+ can be used during image creation to inspect and
+ modify the EFI Boot Guard configuration data.
+
+ https://github.com/siemens/efibootguard
diff --git a/boot/efibootguard/efibootguard.hash b/boot/efibootguard/efibootguard.hash
new file mode 100644
index 0000000000..6f5a5cf25c
--- /dev/null
+++ b/boot/efibootguard/efibootguard.hash
@@ -0,0 +1,3 @@
+# Locally calculated
+sha256 6c68c541311dcc8c2be0042f7887acc2a24d2ac68a88d426380fdbda9f476ae8 efibootguard-0.22.tar.gz
+sha256 8177f97513213526df2cf6184d8ff986c675afb514d4e68a404010521b880643 COPYING
diff --git a/boot/efibootguard/efibootguard.mk b/boot/efibootguard/efibootguard.mk
new file mode 100644
index 0000000000..f12c078632
--- /dev/null
+++ b/boot/efibootguard/efibootguard.mk
@@ -0,0 +1,67 @@
+################################################################################
+#
+# efibootguard
+#
+################################################################################
+
+EFIBOOTGUARD_VERSION = 0.22
+EFIBOOTGUARD_SITE = $(call github,siemens,efibootguard,refs/tags/v$(EFIBOOTGUARD_VERSION))
+EFIBOOTGUARD_LICENSE = GPL-2.0-only
+EFIBOOTGUARD_LICENSE_FILES = COPYING
+EFIBOOTGUARD_CPE_ID_VENDOR = siemens
+
+EFIBOOTGUARD_DEPENDENCIES = \
+ gnu-efi \
+ pciutils \
+ host-autoconf-archive \
+ host-pkgconf
+
+EFIBOOTGUARD_AUTORECONF = YES
+
+EFIBOOTGUARD_AUTORECONF_OPTS = --include=$(HOST_DIR)/share/autoconf-archive
+
+EFIBOOTGUARD_CONF_OPTS = \
+ --with-gnuefi-sys-dir=$(STAGING_DIR) \
+ --with-gnuefi-include-dir=$(STAGING_DIR)/usr/include/efi \
+ --with-gnuefi-lib-dir=$(STAGING_DIR)/usr/lib \
+ --disable-completion \
+ --disable-tests
+
+EFIBOOTGUARD_CONF_ENV = \
+ LDFLAGS="$(LDFLAGS) -no-pie"
+
+ifeq ($(BR2_TARGET_EFIBOOTGUARD_INSTALL_TOOLS),y)
+EFIBOOTGUARD_INSTALL_TARGET = YES
+
+# bg_gen_unified_kernel is mainly useful when assembling a UKI/image - do not
+# install it into the runtime target filesystem.
+define EFIBOOTGUARD_REMOVE_BG_GEN_UNIFIED_KERNEL
+ rm -rf $(TARGET_DIR)/usr/bin/bg_gen_unified_kernel
+endef
+EFIBOOTGUARD_POST_INSTALL_TARGET_HOOKS += EFIBOOTGUARD_REMOVE_BG_GEN_UNIFIED_KERNEL
+else
+EFIBOOTGUARD_INSTALL_TARGET = NO
+endif
+
+EFIBOOTGUARD_INSTALL_IMAGES = YES
+define EFIBOOTGUARD_INSTALL_IMAGES_CMDS
+ $(INSTALL) -m 0644 $(@D)/efibootguard*.efi $(BINARIES_DIR)
+ $(INSTALL) -m 0644 $(@D)/kernel-stub*.efi $(BINARIES_DIR)
+endef
+
+HOST_EFIBOOTGUARD_DEPENDENCIES = \
+ host-autoconf-archive \
+ host-pkgconf \
+ host-python3
+
+HOST_EFIBOOTGUARD_AUTORECONF = YES
+
+HOST_EFIBOOTGUARD_AUTORECONF_OPTS = --include=$(HOST_DIR)/share/autoconf-archive
+
+HOST_EFIBOOTGUARD_CONF_OPTS = \
+ --disable-bootloader \
+ --disable-completion \
+ --disable-tests
+
+$(eval $(autotools-package))
+$(eval $(host-autotools-package))

--
2.53.0

Christopher Obbard

unread,
Jun 17, 2026, 9:23:45 PM (4 days ago) Jun 17
to buil...@buildroot.org, James Hilliard, Thomas Petazzoni, Yegor Yefremov, efibootg...@googlegroups.com, Christopher Obbard
osslsigncode is an OpenSSL-based Authenticode signing tool for PE
binaries. It can be used during image assembly to sign EFI binaries,
such as bootloaders or unified kernel images, for UEFI Secure Boot.

Add osslsigncode as a host-only package, since its main Buildroot use
case is signing generated artifacts on the build host.

Signed-off-by: Christopher Obbard <obb...@gmail.com>
---
DEVELOPERS | 1 +
package/Config.in.host | 1 +
package/osslsigncode/Config.in.host | 9 +++++++++
package/osslsigncode/osslsigncode.hash | 3 +++
package/osslsigncode/osslsigncode.mk | 21 +++++++++++++++++++++
5 files changed, 35 insertions(+)

diff --git a/DEVELOPERS b/DEVELOPERS
index 1c77d02afc..8cba141a77 100644
--- a/DEVELOPERS
+++ b/DEVELOPERS
@@ -708,6 +708,7 @@ F: package/perl-x10/
N: Christopher Obbard <obb...@gmail.com>
F: boot/efibootguard/
F: package/dtui/
+F: package/osslsigncode/

N: Colin Foster <colin....@in-advantage.com>
F: package/python-tftpy/
diff --git a/package/Config.in.host b/package/Config.in.host
index df57cc0c17..2b88adbaf3 100644
--- a/package/Config.in.host
+++ b/package/Config.in.host
@@ -81,6 +81,7 @@ menu "Host utilities"
source "package/omap-u-boot-utils/Config.in.host"
source "package/openocd/Config.in.host"
source "package/opkg-utils/Config.in.host"
+ source "package/osslsigncode/Config.in.host"
source "package/pahole/Config.in.host"
source "package/parted/Config.in.host"
source "package/patchelf/Config.in.host"
diff --git a/package/osslsigncode/Config.in.host b/package/osslsigncode/Config.in.host
new file mode 100644
index 0000000000..6606402bcc
--- /dev/null
+++ b/package/osslsigncode/Config.in.host
@@ -0,0 +1,9 @@
+config BR2_PACKAGE_HOST_OSSLSIGNCODE
+ bool "host osslsigncode"
+ help
+ osslsigncode is an OpenSSL-based Authenticode signing tool for
+ PE, MSI, CAB and CAT files. It can be used at image assembly
+ time to sign PE/EFI binaries (such as bootloaders and unified
+ kernel images) for UEFI Secure Boot.
+
+ https://github.com/mtrojnar/osslsigncode
diff --git a/package/osslsigncode/osslsigncode.hash b/package/osslsigncode/osslsigncode.hash
new file mode 100644
index 0000000000..2564b5cef7
--- /dev/null
+++ b/package/osslsigncode/osslsigncode.hash
@@ -0,0 +1,3 @@
+# Locally computed:
+sha256 ee95638b8bec0c019ddf28cb14988645abbd180dcd017536338b7d0d5eaaea96 osslsigncode-2.13.tar.gz
+sha256 8ceb4b9ee5adedde47b31e975c1d90c73ad27b6b165a1dcd80c7c545eb65b903 COPYING.txt
diff --git a/package/osslsigncode/osslsigncode.mk b/package/osslsigncode/osslsigncode.mk
new file mode 100644
index 0000000000..b8843a25b4
--- /dev/null
+++ b/package/osslsigncode/osslsigncode.mk
@@ -0,0 +1,21 @@
+################################################################################
+#
+# osslsigncode
+#
+################################################################################
+
+OSSLSIGNCODE_VERSION = 2.13
+OSSLSIGNCODE_SITE = $(call github,mtrojnar,osslsigncode,$(OSSLSIGNCODE_VERSION))
+OSSLSIGNCODE_LICENSE = GPL-3.0+ with OpenSSL exception
+OSSLSIGNCODE_LICENSE_FILES = COPYING.txt
+
+# osslsigncode is generally used at image assembly time to Authenticode-sign
+# PE/EFI binaries (e.g. for UEFI Secure Boot) so only a host build is provided.
+HOST_OSSLSIGNCODE_DEPENDENCIES = host-openssl host-zlib
+
+# Upstream installs the bash completion file to an absolute destination; instead
+# point it inside $(HOST_DIR).
+HOST_OSSLSIGNCODE_CONF_OPTS = \
+ -DBASH_COMPLETION_USER_DIR=$(HOST_DIR)/share/bash-completion/completions
+
+$(eval $(host-cmake-package))

--
2.53.0

Christopher Obbard

unread,
Jun 17, 2026, 9:23:47 PM (4 days ago) Jun 17
to buil...@buildroot.org, James Hilliard, Thomas Petazzoni, Yegor Yefremov, efibootg...@googlegroups.com, Christopher Obbard
Add an example recipe (based on configs/pc_x86_64_efi_defconfig) to
generate an x86-64 image which boots the system using the EFI Boot Guard
bootloader. The recipe is an example of how to create an image using
EFI Boot Guard, including how to create the disk image & how to configure
the bootloader.

The created example image contains two boot slots; one of which contains
the environment built by Buildroot and the other is an empty, dummy slot
(e.g. cannot be booted from).

EFI Boot Guard provides a tool for generating UKI images, which can then
be signed for Secure Boot. Enable the UKI generation and signing in the
example recipe.

Also add instructions to boot the example image in QEMU.

Signed-off-by: Christopher Obbard <obb...@gmail.com>
---
DEVELOPERS | 2 +
board/pc-efibootguard/genimage.cfg | 56 ++++
board/pc-efibootguard/linux.fragment | 29 +++
board/pc-efibootguard/post-image.sh | 162 ++++++++++++
board/pc-efibootguard/readme.txt | 281 +++++++++++++++++++++
.../etc/systemd/system.conf.d/10-watchdog.conf | 7 +
configs/pc_x86_64_efibootguard_defconfig | 24 ++
7 files changed, 561 insertions(+)

diff --git a/DEVELOPERS b/DEVELOPERS
index 8cba141a77..e69923dcd0 100644
--- a/DEVELOPERS
+++ b/DEVELOPERS
@@ -706,7 +706,9 @@ F: package/perl-time-parsedate/
F: package/perl-x10/

N: Christopher Obbard <obb...@gmail.com>
+F: board/pc-efibootguard/
F: boot/efibootguard/
+F: configs/pc_x86_64_efibootguard_defconfig
F: package/dtui/
F: package/osslsigncode/

diff --git a/board/pc-efibootguard/genimage.cfg b/board/pc-efibootguard/genimage.cfg
new file mode 100644
index 0000000000..096901b27d
--- /dev/null
+++ b/board/pc-efibootguard/genimage.cfg
@@ -0,0 +1,56 @@
+image EFI.vfat {
+ vfat {}
+
+ size = 16M
+ srcpath = "output/images/efi-part"
+}
+
+image boot-a.vfat {
+ vfat {}
+
+ size = 32M
+ srcpath = "output/images/boot-a-part"
+}
+
+image boot-b.vfat {
+ vfat {}
+
+ size = 32M
+ srcpath = "output/images/boot-b-part"
+}
+
+image disk.img {
+ hdimage {
+ partition-table-type = "gpt"
+ }
+
+ partition EFI {
+ image = "EFI.vfat"
+ partition-type-uuid = esp
+ offset = 32K
+ bootable = true
+ }
+
+ partition boot-a {
+ partition-type-uuid = fat32
+ image = "boot-a.vfat"
+ }
+
+ # boot-b is an empty placeholder
+ partition boot-b {
+ partition-type-uuid = fat32
+ image = "boot-b.vfat"
+ }
+
+ partition system-a {
+ partition-type-uuid = root-x86-64
+ image = "rootfs.ext4"
+ size = 120M
+ }
+
+ # system-b is an empty placeholder
+ partition system-b {
+ partition-type-uuid = root-x86-64
+ size = 120M
+ }
+}
diff --git a/board/pc-efibootguard/linux.fragment b/board/pc-efibootguard/linux.fragment
new file mode 100644
index 0000000000..ec9dbc1e12
--- /dev/null
+++ b/board/pc-efibootguard/linux.fragment
@@ -0,0 +1,29 @@
+# Build the kernel with the EFI Stub.
+CONFIG_EFI=y
+CONFIG_EFI_STUB=y
+CONFIG_EFIVAR_FS=y
+CONFIG_EFI_PARTITION=y
+
+# EFI Boot Guard user-space tools (bg_printenv/bg_setenv) modifies FAT config
+# partitions.
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+
+# Enable a text console on the framebuffer handed over by UEFI GOP.
+# On systems where the firmware exposes the boot display as a GOP framebuffer,
+# Linux registers it via sysfb/simple-framebuffer and simpledrm binds to it.
+# This includes QEMU/OVMF with the default emulated VGA display.
+CONFIG_SYSFB_SIMPLEFB=y
+CONFIG_DRM=y
+CONFIG_DRM_SIMPLEDRM=y
+CONFIG_DRM_FBDEV_EMULATION=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+
+# Enable the Intel 6300ESB watchdog driver (which can be emulated by QEMU).
+CONFIG_WATCHDOG=y
+CONFIG_I6300ESB_WDT=y
diff --git a/board/pc-efibootguard/post-image.sh b/board/pc-efibootguard/post-image.sh
new file mode 100755
index 0000000000..2b2a8399f3
--- /dev/null
+++ b/board/pc-efibootguard/post-image.sh
@@ -0,0 +1,162 @@
+#!/bin/sh
+# Generates a raw disk image with an ESP containing the EFI Boot Guard
+# bootloader binary, two EFI Boot Guard slot config partitions and two
+# filesystem partitions. This allows for "A/B" booting.
+#
+# The first slot is populated with the filesystem generated by the Buildroot
+# build and the second slot is an empty placeholder.
+#
+# With SIGN_BINARIES=1, the bootloader and kernel artifacts are signed with
+# user-generated keys. Otherwise, the artifacts are installed unsigned.
+#
+# With UKI=1, EFI Boot Guard is configured to boot a Unified Kernel Image
+# (kernel & command line bundled into one binary) which is suitable for secure
+# boot. Otherwise, EFI Boot Guard will boot the kernel & command line specified
+# in the slot config.
+set -e
+
+BOARD_DIR="$(dirname "$0")"
+
+# Kernel command line parameters.
+# The rootfs is mounted using a hard-coded partlabel for simplicity.
+# This will need to be modified when generating images for other slots.
+KERNEL_CMDLINE="root=PARTLABEL=system-a"
+
+# Hardware watchdog timeout, in seconds, armed by EFI Boot Guard before it
+# boots the kernel. Set to 0 to disable arming the watchdog.
+WATCHDOG_TIMEOUT=120
+
+# Kernel image format.
+# Set to 1 to build a Unified Kernel Image (kernel & command line bundled into
+# one PE binary).
+# Set to 0 to use the raw kernel image instead.
+UKI=1
+
+# Sign EFI Boot Guard binary and kernel artifact.
+# Set to 1 to sign the artifacts; 0 to disable signing.
+SIGN_BINARIES=1
+
+# Staging directory for the EFI System Partition contents.
+EFI_DIR="${BINARIES_DIR}/efi-part"
+
+# Persistent location for the user's UEFI Secure Boot keys.
+KEYS_DIR="${BINARIES_DIR}/secure-boot-keys"
+
+# Sign a PE/EFI binary with the db key.
+sign_pe() {
+ input="$1"
+ output="$2"
+ "${HOST_DIR}/bin/osslsigncode" sign -h sha256 \
+ -key "${KEYS_DIR}/db.key" \
+ -certs "${KEYS_DIR}/db.crt" \
+ -in "$input" \
+ -out "$output"
+}
+
+# Generate EFI Boot Guard slot configuration.
+generate_slot_config() {
+ slot_dir="$1"
+ label="$2"
+ revision="$3"
+ ustate="$4"
+ kernel="$5"
+ args="${KERNEL_CMDLINE}"
+
+ # When booting a UKI, EFI Boot Guard ignores the kernel command line set in
+ # the slot config and instead reads the command line embedded in the UKI.
+ # If the slot config has non-empty args entry, EFI Boot Guard warns during
+ # boot. So if we are building a UKI, generate the slot config with an empty
+ # args parameter.
+ if [ "${UKI}" -eq 1 ]; then
+ args=""
+ fi
+
+ mkdir -p "${slot_dir}"
+ printf "%s" "${label}" | iconv -f ascii -t UTF-16LE > "${slot_dir}/EFILABEL"
+
+ "${HOST_DIR}/bin/bg_setenv" \
+ --verbose \
+ --watchdog="${WATCHDOG_TIMEOUT}" \
+ --filepath="${slot_dir}/BGENV.DAT" \
+ --revision="${revision}" \
+ --ustate="${ustate}" \
+ --kernel="${kernel}" \
+ --args="${args}"
+}
+
+# Reset staging directories.
+rm -rf \
+ "${EFI_DIR}" \
+ "${BINARIES_DIR}/boot-a-part" \
+ "${BINARIES_DIR}/boot-b-part"
+mkdir -p \
+ "${EFI_DIR}/EFI/BOOT" \
+ "${BINARIES_DIR}/boot-a-part" \
+ "${BINARIES_DIR}/boot-b-part"
+
+# If signing is enabled, sign the EFI Boot Guard binary and install it into the
+# ESP. Otherwise install the unsigned binary into the ESP.
+if [ "${SIGN_BINARIES}" -eq 1 ]; then
+ # Ensure the Secure Boot keys exist.
+ # These must be generated by the user beforehand; see the readme for
+ # instructions.
+ for key in db.key db.crt PK.cer KEK.cer db.cer; do
+ if [ ! -f "${KEYS_DIR}/${key}" ]; then
+ echo "ERROR: Secure Boot key '${KEYS_DIR}/${key}' not found." >&2
+ echo "Generate the Secure Boot keys before building; see the readme." >&2
+ exit 1
+ fi
+ done
+
+ # Sign the EFI Boot Guard bootloader and install it into the ESP.
+ sign_pe "${BINARIES_DIR}/efibootguardx64.efi" \
+ "${EFI_DIR}/EFI/BOOT/BOOTX64.EFI"
+
+ # Copy the certificates into the ESP to allow users to enrol them into UEFI
+ # firmware.
+ mkdir -p "${EFI_DIR}/keys"
+ cp "${KEYS_DIR}/PK.cer" "${KEYS_DIR}/KEK.cer" "${KEYS_DIR}/db.cer" \
+ "${EFI_DIR}/keys/"
+else
+ # If unsigned, just install the bootloader binary into the ESP.
+ install -m 0644 "${BINARIES_DIR}/efibootguardx64.efi" \
+ "${EFI_DIR}/EFI/BOOT/BOOTX64.EFI"
+fi
+
+# Build a Unified Kernel Image (bundling the EFI Boot Guard stub, raw kernel and
+# command line).
+if [ "${UKI}" -eq 1 ]; then
+ "${HOST_DIR}/bin/bg_gen_unified_kernel" \
+ "${BINARIES_DIR}/kernel-stubx64.efi" \
+ "${BINARIES_DIR}/bzImage" \
+ "${BINARIES_DIR}/kernel-uki.efi" \
+ --cmdline "${KERNEL_CMDLINE}"
+
+ KERNEL_IMAGE="kernel-uki.efi"
+else
+ # If not building a UKI, use the raw kernel image.
+ KERNEL_IMAGE="bzImage"
+fi
+
+# Copy the kernel image into boot-a (optionally signing the image).
+if [ "${SIGN_BINARIES}" -eq 1 ]; then
+ sign_pe "${BINARIES_DIR}/${KERNEL_IMAGE}" "${BINARIES_DIR}/boot-a-part/${KERNEL_IMAGE}"
+else
+ cp "${BINARIES_DIR}/${KERNEL_IMAGE}" "${BINARIES_DIR}/boot-a-part/${KERNEL_IMAGE}"
+fi
+
+# Generate the EFI Boot Guard slot configuration.
+# Set boot-a ustate=OK, the path to the kernel binary and (optionally; if not
+# booting a UKI) the kernel command line parameter.
+generate_slot_config \
+ "${BINARIES_DIR}/boot-a-part" \
+ "boot-a" "2" "OK" \
+ "C:boot-a:${KERNEL_IMAGE}"
+
+# Set boot-b ustate=FAILED so EFI Boot Guard doesn't boot it.
+generate_slot_config \
+ "${BINARIES_DIR}/boot-b-part" \
+ "boot-b" "1" "FAILED" ""
+
+# Generate the disk image.
+support/scripts/genimage.sh -c "${BOARD_DIR}/genimage.cfg"
diff --git a/board/pc-efibootguard/readme.txt b/board/pc-efibootguard/readme.txt
new file mode 100644
index 0000000000..f0fdd675bd
--- /dev/null
+++ b/board/pc-efibootguard/readme.txt
@@ -0,0 +1,281 @@
+EFI Boot Guard Example Recipe
+=============================
+
+This recipe creates a basic x86 disk image using EFI Boot Guard[1] as the
+bootloader with two root filesystem slots.
+
+The image is intended to demonstrate a typical A/B boot layout. The first slot
+is populated with the root filesystem generated as part of the Buildroot build.
+The second slot is intentionally left empty so that a future update tool can
+install an alternate root filesystem there.
+
+The recipe also creates the EFI system partition and installs the EFI Boot Guard
+bootloader and configuration needed to select and boot one of the available slots.
+Each slot has its own EFI Boot Guard environment, containing the kernel image and
+configuration.
+
+This example is deliberately minimal. It is intended as a reference for users who
+want to integrate EFI Boot Guard into their own platform-specific images, rather
+than as a complete production-ready setup. It was designed to be run in QEMU and
+may need additional changes to run on real hardware.
+
+By default this example is built with UEFI Secure Boot support enabled. In that
+mode, both the EFI Boot Guard and kernel binaries are signed during image
+generation so that they can be verified by the firmware before execution.
+
+Secure Boot support in this recipe is primarily intended for development and
+testing. These instructions contain the steps to generate signed EFI binaries,
+but a production system should use platform-specific key management, key
+enrolment and signing infrastructure, which is out of scope of this document.
+In particular, the example keys must not be reused for production images.
+
+
+Build the image
+===============
+
+Configure Buildroot with:
+
+ $ make pc_x86_64_efibootguard_defconfig
+
+Build the image with:
+
+ $ make
+
+The raw disk image is available under output/images/disk.img.
+
+
+Emulation in QEMU
+=================
+
+Emulate the system in QEMU with:
+
+ $ qemu-system-x86_64 \
+ -machine q35,smm=on \
+ -m size=512M \
+ -drive if=pflash,format=raw,readonly=on,file=</path/to/OVMF_CODE.fd> \
+ -drive file=output/images/disk.img,if=virtio,format=raw \
+ -boot menu=on \
+ -device i6300esb \
+ -action watchdog=reset
+
+Note that </path/to/OVMF_CODE.fd> needs to point to a valid x86_64 UEFI firmware
+image for QEMU. It may be provided by your distribution as an edk2 or OVMF
+package, in a path such as /usr/share/OVMF/OVMF_CODE_4M.fd on Debian.
+
+
+Boot process & slot configuration
+=================================
+
+This example uses EFI Boot Guard as the first-stage UEFI boot application for
+A/B boot selection. The disk image contains a shared EFI System Partition, two
+small EFI Boot Guard configuration partitions and two root filesystem slots:
+
+* EFI System Partition ("EFI")
+ Contains the EFI Boot Guard bootloader binary.
+
+* EFI Boot Guard config partition A ("boot-a")
+ Contains the boot environment for slot A, including the EFI Boot Guard slot
+ configuration and kernel image built by Buildroot.
+
+* EFI Boot Guard config partition B ("boot-b")
+ Contains the boot environment for slot B, including the EFI Boot Guard slot
+ configuration to disable booting from slot B.
+
+* rootfs A ("system-a")
+ First root filesystem slot. Populated with the target filesystem built by
+ Buildroot.
+
+* rootfs B ("system-b")
+ Second root filesystem slot. Not populated by default.
+
+The firmware first loads EFI Boot Guard from the EFI System Partition. EFI
+Boot Guard then reads its slot metadata from the configuration partitions and
+selects the best bootable slot. Each slot has an EFI Boot Guard environment
+file containing the slot label, revision, ustate, watchdog timeout, boot file
+and optional kernel arguments.
+
+The slot's ustate controls whether a slot is considered bootable. A newly installed
+slot is normally marked as pending/testing and, if enabled in the slot config,
+a watchdog is started on the device. EFI Boot Guard attempts to boot the slot.
+
+Once Linux has booted successfully, user-space must mark the slot's ustate as
+OK. If the system fails to boot or the watchdog expires before the slot is
+confirmed, EFI Boot Guard can fall back to the previous working slot or refuse
+to boot.
+
+The slot environments are generated at image assembly time using the EFI Boot
+Guard host tools. They are intentionally generated outside the target rootfs
+because they describe the final disk image layout rather than files installed
+inside a single root filesystem. By default, the recipe sets slot A with ustate
+of OK.
+
+For more information on EFI Boot Guard configuration, see the upstream
+documentation[1].
+
+
+Watchdog
+========
+
+EFI Boot Guard can arm a hardware watchdog before handing control to Linux. The
+watchdog protects against a system that starts booting a bad slot but then hangs
+before userspace can report success or failure.
+
+If Linux boots correctly, userspace must take over or disarm the watchdog before
+the timeout expires. With systemd this is usually done by enabling the runtime
+watchdog, for example by setting RuntimeWatchdogSec. The runtime watchdog timeout
+should be shorter than the EFI Boot Guard watchdog timeout so that systemd starts
+feeding the watchdog in time.
+
+By default, the recipe configures EFI Boot Guard to arm a 120 second watchdog and
+enables a systemd runtime watchdog value of 60 seconds to give Linux enough time
+to boot and take over the device.
+
+EFI Boot Guard has limited support for hardware watchdogs and will refuse to
+boot the slot if no supported hardware watchdog is found and the slot has the
+watchdog parameter configured to >0. To disable the watchdog at image generation
+time, set WATCHDOG_TIMEOUT in post_image.sh to 0. This can be useful during
+development but removes one of the main safety mechanisms for A/B rollback
+testing.
+
+When testing under QEMU, an emulated watchdog can be enabled with:
+
+ -device i6300esb
+ -action watchdog=reset
+
+This causes QEMU to reset the virtual machine if the watchdog expires.
+
+
+Unified Kernel Image (UKI)
+==========================
+
+By default this recipe builds the boot payload as a Unified Kernel Image (UKI).
+A UKI bundles a kernel, initramfs, device tree(s) and kernel command line into a
+single PE/COFF EFI binary.
+
+For this example recipe, only the kernel image and command line are bundled
+into the UKI binary.
+
+When UKI support is disabled, EFI Boot Guard loads a normal kernel image and
+passes the kernel command line from the EFI Boot Guard environment.
+
+UKIs are useful when combined with Secure Boot because the whole boot payload
+can be signed as one EFI binary.
+
+
+UEFI Secure Boot
+================
+
+The recipe by default will sign the EFI binaries with Secure Boot keys. When
+enabled, the recipe:
+
+* uses Secure Boot keys: a Platform Key (PK), Key Exchange Key (KEK) and signature
+ database (db) key/certificate pair.
+* signs the EFI Boot Guard EFI binary and the UKI (or other EFI boot payload)
+ with the db key.
+* installs the signed EFI binaries.
+* copies the DER certificates needed for UEFI firmware enrolment into the EFI
+ System Partition under \keys.
+
+Secure Boot verifies EFI binaries before they are executed. In this setup, the
+firmware verifies EFI Boot Guard and EFI Boot Guard then loads the selected
+signed boot payload.
+
+The following instructions can be ran on the host to generate dummy self-signed
+key/certificate pairs. These are intended for testing only and must not be used
+in production:
+
+ $ export KEYS_DIR=output/images/secure-boot-keys
+ $ mkdir -p "${KEYS_DIR}"
+ $ for name in PK KEK db; do
+ openssl req -new -x509 -newkey rsa:2048 -sha256 \
+ -days 3650 -nodes \
+ -subj "/CN=pc-efibootguard ${name}/" \
+ -keyout "${KEYS_DIR}/${name}.key" \
+ -out "${KEYS_DIR}/${name}.crt"
+ openssl x509 \
+ -in "${KEYS_DIR}/${name}.crt" \
+ -outform DER \
+ -out "${KEYS_DIR}/${name}.cer"
+ done
+
+The generated keys are stored under output/images/secure-boot-keys/. They are
+created once and reused on subsequent builds. These files are removed with
+"make clean".
+
+
+Testing under QEMU
+------------------
+
+Secure Boot must be enforced by the firmware, which in QEMU requires the
+"secboot" OVMF build together with SMM and a q35 machine. The OVMF variables
+file is persistent, so make a fresh writable copy of the variable store first.
+If the disk layout, boot entries or enrolled keys change, remove the old
+OVMF_VARS.fd and copy a fresh one before retesting.
+
+ $ cp </path/to/OVMF_VARS_4M.fd> OVMF_VARS.fd
+
+Then run QEMU:
+
+ $ qemu-system-x86_64 \
+ -machine q35,smm=on \
+ -m 512M \
+ -global driver=cfi.pflash01,property=secure,value=on \
+ -drive if=pflash,format=raw,unit=0,readonly=on,file=</path/to/OVMF_CODE.secboot.fd> \
+ -drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd \
+ -drive file=output/images/disk.img,if=virtio,format=raw \
+ -boot menu=on \
+ -device i6300esb \
+ -action watchdog=reset
+
+On the very first boot Secure Boot is not yet enabled and the keys must first be
+enrolled once. The DER certificates are copied into the EFI System Partition
+under \keys for convenience. Press ESC at the logo and choose "EFI Firmware Setup"
+to reach the UEFI menu, then enrol the keys:
+
+ Device Manager
+ -> Secure Boot Configuration
+ -> Secure Boot Mode -> Custom Mode
+ -> Custom Secure Boot Options
+ -> DB Options -> Enroll Signature -> Enroll Signature Using File
+ -> select FS0:\keys\db.cer -> Commit Changes
+ -> KEK Options -> ... FS0:\keys\KEK.cer -> Commit Changes
+ -> PK Options -> ... FS0:\keys\PK.cer -> Commit Changes
+
+Enrol the db and KEK before the PK. Enrolling the PK switches the firmware into
+User Mode and activates Secure Boot. Reset the machine - the firmware now
+verifies the signed EFI Boot Guard bootloader, which in turn loads the signed
+kernel image.
+
+
+EFI Boot Guard user-space tools
+===============================
+
+The example image includes the EFI Boot Guard user-space tools. These can be
+used to inspect and update the slot configuration.
+
+bg_printenv prints the EFI Boot Guard slot config (of all slots):
+
+ # bg_printenv
+
+
+bg_setenv can be used to update a slot's configuration, including its ustate and
+revision. For example, the following commands mark both slots as OK and make
+slot 0 (e.g. the first configuration partition) the preferred slot to boot:
+
+ # bg_setenv --preserve --part 0 --ustate OK --revision 1
+ # bg_setenv --preserve --part 1 --ustate OK --revision 0
+
+
+Note that without --preserve bg_setenv will rewrite the slot config rather than
+updating only the options specified on the command line. Any omitted settings
+may be written with their default or empty values, so make sure to pass all
+options to avoid producing an incomplete environment.
+
+An update system could use these tools to switch the preferred boot slot after
+installing an update and to mark a slot's ustate as OK once the newly installed
+slot boots successfully.
+
+For more information on configuring EFI Boot Guard, see the upstream
+documentation[1].
+
+[1]: https://github.com/siemens/efibootguard/blob/master/README.md
diff --git a/board/pc-efibootguard/rootfs-overlay/etc/systemd/system.conf.d/10-watchdog.conf b/board/pc-efibootguard/rootfs-overlay/etc/systemd/system.conf.d/10-watchdog.conf
new file mode 100644
index 0000000000..4ad3f4ceb8
--- /dev/null
+++ b/board/pc-efibootguard/rootfs-overlay/etc/systemd/system.conf.d/10-watchdog.conf
@@ -0,0 +1,7 @@
+[Manager]
+# Arm the hardware watchdog and ping it.
+# The hardware timeout is set to RuntimeWatchdogSec and is pinged at half
+# that interval.
+RuntimeWatchdogSec=1min
+# Keep the watchdog armed across reboot/shutdown so a hung shutdown resets.
+RebootWatchdogSec=5min
diff --git a/configs/pc_x86_64_efibootguard_defconfig b/configs/pc_x86_64_efibootguard_defconfig
new file mode 100644
index 0000000000..44d8c9c860
--- /dev/null
+++ b/configs/pc_x86_64_efibootguard_defconfig
@@ -0,0 +1,24 @@
+BR2_x86_64=y
+BR2_TOOLCHAIN_EXTERNAL=y
+BR2_TOOLCHAIN_EXTERNAL_BOOTLIN_X86_64_GLIBC_STABLE=y
+BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
+BR2_INIT_SYSTEMD=y
+BR2_TARGET_GENERIC_GETTY_PORT="tty1"
+BR2_ROOTFS_OVERLAY="board/pc-efibootguard/rootfs-overlay"
+BR2_ROOTFS_POST_IMAGE_SCRIPT="board/pc-efibootguard/post-image.sh"
+BR2_LINUX_KERNEL=y
+BR2_LINUX_KERNEL_DEFCONFIG="x86_64"
+BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="board/pc-efibootguard/linux.fragment"
+BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
+BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
+BR2_TARGET_ROOTFS_EXT2=y
+BR2_TARGET_ROOTFS_EXT2_4=y
+BR2_TARGET_ROOTFS_EXT2_SIZE="120M"
+# BR2_TARGET_ROOTFS_TAR is not set
+BR2_TARGET_EFIBOOTGUARD=y
+BR2_TARGET_EFIBOOTGUARD_INSTALL_TOOLS=y
+BR2_TARGET_HOST_EFIBOOTGUARD=y
+BR2_PACKAGE_HOST_DOSFSTOOLS=y
+BR2_PACKAGE_HOST_GENIMAGE=y
+BR2_PACKAGE_HOST_MTOOLS=y
+BR2_PACKAGE_HOST_OSSLSIGNCODE=y

--
2.53.0

Reply all
Reply to author
Forward
0 new messages