From: Mikko Rapeli <mikko.rapeli@linaro.org>
To: openembedded-core@lists.openembedded.org
Cc: Michelle Lin <michelle.linto91@gmail.com>,
Erik Schilling <erik.schilling@linaro.org>,
Mikko Rapeli <mikko.rapeli@linaro.org>
Subject: [PATCH 2/2] uki.bbclass: add class for building Unified Kernel Images (UKI)
Date: Mon, 2 Sep 2024 13:58:25 +0300 [thread overview]
Message-ID: <20240902105825.40177-3-mikko.rapeli@linaro.org> (raw)
In-Reply-To: <20240902105825.40177-1-mikko.rapeli@linaro.org>
From: Michelle Lin <michelle.linto91@gmail.com>
This class calls systemd ukify tool, which will combine
kernel/initrd/stub components to build the UKI. To sign the UKI
(i.e. SecureBoot), the keys/cert files can be specified
in a configuration file or UEFI binary signing can be done
via separate steps, see qemuarm64-secureboot in meta-arm.
UKIs are loaded by UEFI firmware on target which can improve
security by loading only correctly signed kernel, initrd and kernel
command line.
Using systemd-measure to pre-calculate TPM PCR values and sign them is
not supported since that requires a TPM device on the build host. Thus
"ConditionSecurity=measured-uki" default from systemd 256 does not work
but "ConditionSecurity=tpm2" in combination with secure boot will.
These can be used to boot securely into systemd-boot, kernel, kernel
command line and initrd which then securely mounts a read-only dm-verity
/usr partition and creates a TPM encrypted read-write / rootfs.
Tested via qemuarm64-secureboot in meta-arm with
https://lists.yoctoproject.org/g/meta-arm/topic/patch_v3_02_13/108031399
and a few more changes needed, will be posted separately.
Signed-off-by: Michelle Lin <michelle.linto91@gmail.com>
Acked-by: Erik Schilling <erik.schilling@linaro.org>
Signed-off-by: Mikko Rapeli <mikko.rapeli@linaro.org>
---
meta/classes-recipe/uki.bbclass | 158 ++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
create mode 100644 meta/classes-recipe/uki.bbclass
diff --git a/meta/classes-recipe/uki.bbclass b/meta/classes-recipe/uki.bbclass
new file mode 100644
index 0000000000..8d4bf317fe
--- /dev/null
+++ b/meta/classes-recipe/uki.bbclass
@@ -0,0 +1,158 @@
+# Unified kernel image (UKI) class
+#
+# This bbclass merges kernel, initrd etc as a UKI standard UEFI binary,
+# to be loaded with UEFI firmware on target. SecureBoot signing is
+# supported via add ons. TPM PCR pre-calculation is not supported since
+# systemd-measure tooling is meant to run on target, not in cross compile
+# environment.
+#
+# See:
+# https://www.freedesktop.org/software/systemd/man/latest/ukify.html
+# https://uapi-group.org/specifications/specs/unified_kernel_image/
+#
+# The UKI is composed from
+# - an UEFI stub
+# The linux kernel can generate a UEFI stub, however the one from systemd-boot can fetch
+# the command line from a separate section of the EFI application, avoiding the need to
+# rebuild the kernel.
+# - the kernel
+# - an initramfs
+# - other metadata (e.g. PCR measurements)
+#
+# Usage instructions:
+# - requires UEFI compatible firmware on target, e.g. qemuarm64-secureboot from meta-arm
+# - Distro config:
+# INIT_MANAGER = "systemd"
+# DISTRO_FEATURES += "systemd"
+# DISTRO_FEATURES_NATIVE += "systemd"
+# DISTRO_FEATURES += "efi"
+# DISTRO_FEATURES += "uki"
+# INITRAMFS_IMAGE ?= "core-image-minimal-initramfs"
+# HOSTTOOLS += "getent ping"
+# EFI_PROVIDER = "systemd-boot"
+# - image recipe:
+# INHERIT_UKI = "${@bb.utils.contains('DISTRO_FEATURES', 'uki', 'uki', '', d)}"
+# inherit ${INHERIT_UKI}
+# - qemuboot/runqemu changes in image recipe:
+# # Detected by passing kernel parameter
+# QB_KERNEL_ROOT = ""
+# # kernel is in the image, should not be loaded separately
+# QB_DEFAULT_KERNEL = "none"
+# - for UEFI secure boot, systemd-boot, uki and linux kernel need
+# to be signed with sbsign (recipe available from meta-secure-core,
+# see also qemuarm64-secureboot from meta-arm)
+
+DEPENDS += "\
+ systemd \
+ systemd-boot \
+ systemd-boot-native \
+ virtual/${TARGET_PREFIX}binutils \
+ virtual/kernel \
+"
+
+REQUIRED_DISTRO_FEATURES += "usrmerge systemd uki"
+
+inherit features_check image-artifact-names
+require ../conf/image-uefi.conf
+
+INITRAMFS_IMAGE ?= "core-image-minimal-initramfs"
+
+INITRD_ARCHIVE ?= "${INITRAMFS_IMAGE}-${MACHINE}.${INITRAMFS_FSTYPES}"
+
+do_image_complete[depends] += "${INITRAMFS_IMAGE}:do_image_complete"
+
+UKIFY_CMD ?= "ukify build"
+UKI_CONFIG_FILE ?= "${UNPACKDIR}/uki.conf"
+UKI_FILENAME ?= "uki.efi"
+UKI_CMDLINE ?= "rootwait root=/dev/vda2"
+
+IMAGE_EFI_BOOT_FILES ?= "${UKI_FILENAME};EFI/Linux/${UKI_FILENAME}"
+
+do_uki[depends] += " \
+ systemd-boot:do_deploy \
+ virtual/kernel:do_deploy \
+ "
+do_uki[depends] += "${@ '${INITRAMFS_IMAGE}:do_image_complete' if d.getVar('INITRAMFS_IMAGE') else ''}"
+
+# ensure that the build directory is empty everytime we generate a newly-created uki
+do_uki[cleandirs] = "${B}"
+# influence the build directory at the start of the builds
+do_uki[dirs] = "${B}"
+
+# we want to allow specifying files in SRC_URI, such as for signing the UKI
+python () {
+ d.delVarFlag("do_fetch","noexec")
+ d.delVarFlag("do_unpack","noexec")
+}
+
+# main task
+python do_uki() {
+ import glob
+ import bb.process
+
+ # Construct the ukify command
+ ukify_cmd = d.getVar('UKIFY_CMD')
+
+ deploy_dir_image = d.getVar('DEPLOY_DIR_IMAGE')
+
+ # initrd
+ initramfs_image = "%s" % (d.getVar('INITRD_ARCHIVE'))
+ ukify_cmd += " --initrd=%s" % os.path.join(deploy_dir_image, initramfs_image)
+
+ deploy_dir_image = d.getVar('DEPLOY_DIR_IMAGE')
+
+ # Kernel
+ if d.getVar('KERNEL_IMAGETYPE'):
+ kernel = "%s/%s" % (deploy_dir_image, d.getVar('KERNEL_IMAGETYPE'))
+ kernel_version = d.getVar('KERNEL_VERSION')
+ if not os.path.exists(kernel):
+ bb.fatal(f"ERROR: cannot find {kernel}.")
+
+ ukify_cmd += " --linux=%s --uname %s" % (kernel, kernel_version)
+ else:
+ bb.fatal("ERROR - Required argument: KERNEL")
+
+ # Command line
+ cmdline = d.getVar('UKI_CMDLINE')
+ if cmdline:
+ ukify_cmd += " --cmdline='%s'" % cmdline
+
+ # Architecture
+ target_arch = d.getVar('EFI_ARCH')
+ if target_arch:
+ ukify_cmd += " --efi-arch %s" % target_arch
+
+ # systemd stubs from deploy
+ stub = "%s/linux%s.efi.stub" % (d.getVar('DEPLOY_DIR_IMAGE'), target_arch)
+ if not os.path.exists(stub):
+ bb.fatal(f"ERROR: cannot find {stub}.")
+ ukify_cmd += " --stub %s" % stub
+
+ # Add option for dtb
+ if d.getVar('KERNEL_DEVICETREE'):
+ for dtb in d.getVar('KERNEL_DEVICETREE').split():
+ dtb_path = "%s/%s" % (deploy_dir_image, dtb)
+ if not os.path.exists(dtb_path):
+ bb.fatal(f"ERROR: cannot find {dtb_path}.")
+ ukify_cmd += " --devicetree %s" % dtb_path
+
+ # Add option to pass a config file the UKI
+ if os.path.exists(d.getVar('UKI_CONFIG_FILE')):
+ ukify_cmd += " --config=%s" % d.getVar('UKI_CONFIG_FILE')
+
+ # Tools
+ ukify_cmd += " --tools=%s%s/lib/systemd/tools" % (d.getVar("RECIPE_SYSROOT_NATIVE"), d.getVar("prefix"))
+
+ # TODO: tpm2 measure for secure boot, depends on systemd-native and TPM tooling
+ # needed in systemd > 254 to fulfill ConditionSecurity=measured-uki
+ # Requires TPM device on build host, thus not supported at build time.
+ #ukify_cmd += " --measure"
+
+ # Custom UKI name
+ output = " --output=%s/%s" % (d.getVar('DEPLOY_DIR_IMAGE'), d.getVar('UKI_FILENAME'))
+ ukify_cmd += " %s" % output
+
+ # Run the ukify command
+ bb.process.run(ukify_cmd, shell=True)
+}
+addtask uki after do_rootfs before do_deploy do_image_complete do_image_wic
--
2.34.1
next prev parent reply other threads:[~2024-09-02 10:58 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-02 10:58 [PATCH 0/3] systemd uki support Mikko Rapeli
2024-09-02 10:58 ` [PATCH 1/2] systemd-boot-native: add runtime dependency to python3-pefile-native Mikko Rapeli
2024-09-02 10:58 ` Mikko Rapeli [this message]
2024-09-02 11:11 ` [OE-core] [PATCH 2/2] uki.bbclass: add class for building Unified Kernel Images (UKI) Alexander Kanavin
2024-09-02 11:23 ` Mikko Rapeli
2024-09-02 12:01 ` Alexander Kanavin
2024-09-02 12:25 ` Mikko Rapeli
2024-09-02 13:03 ` Alexander Kanavin
2024-09-02 13:15 ` Mikko Rapeli
[not found] ` <17F16FAE8869E0F4.11433@lists.openembedded.org>
2024-09-02 14:14 ` Mikko Rapeli
2024-09-02 14:30 ` Alexander Kanavin
2024-09-04 7:56 ` Mikko Rapeli
2024-09-04 9:17 ` Alexander Kanavin
2024-09-04 10:04 ` Mikko Rapeli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240902105825.40177-3-mikko.rapeli@linaro.org \
--to=mikko.rapeli@linaro.org \
--cc=erik.schilling@linaro.org \
--cc=michelle.linto91@gmail.com \
--cc=openembedded-core@lists.openembedded.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.