Should this also have a wic based selftest or some other way to ensure it works?
Alex On Mon 2. Sep 2024 at 12.58, Mikko Rapeli via lists.openembedded.org <[email protected]> wrote: > From: Michelle Lin <[email protected]> > > 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 <[email protected]> > Acked-by: Erik Schilling <[email protected]> > Signed-off-by: Mikko Rapeli <[email protected]> > --- > 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 > > > > >
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#204095): https://lists.openembedded.org/g/openembedded-core/message/204095 Mute This Topic: https://lists.openembedded.org/mt/108224526/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
