Currently, there is not a class to support the building of unified kernel images. Adding a uki.bbclass to support the creation of UKIs. This class calls the systemd Ukify tool, which will combine the kernel/initrd/stub components to build the UKI. To sign the UKI (i.e. SecureBoot, TPM PCR signing), the keys/cert files are to be specified in a separate configuration file, and the path to the file is passed to the Ukify tool. UKIs are supported by UEFI and can improve security through predicted TPM PCR states, and reduce the build burden due to its single PE binary format.
Signed-off-by: Michelle Lin <[email protected]> --- meta/classes/uki.bbclass | 140 +++++++++++++++++++++++ meta/recipes-core/systemd/systemd_254.bb | 23 ++++ 2 files changed, 163 insertions(+) create mode 100644 meta/classes/uki.bbclass diff --git a/meta/classes/uki.bbclass b/meta/classes/uki.bbclass new file mode 100644 index 0000000000..2eff387c75 --- /dev/null +++ b/meta/classes/uki.bbclass @@ -0,0 +1,140 @@ +# +# Unified kernel image (UKI) class +# +# +# This bbclass is designed to repack an Overlake image as a UKI, to be booted on a qemuarm64 with SecureBoot +# signing and embedded with TPM PCR measurements. +# +# The UKI is composed by: +# - 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) +# +# +# + +# List build time dependencies +DEPENDS += "systemd-native \ + sbsigntool-native \ + virtual/${TARGET_PREFIX}binutils \ + " + +REQUIRED_DISTRO_FEATURES += "usrmerge systemd" + +inherit features_check +require ../conf/image-uefi.conf + +INITRD_IMAGE ?= "core-image-minimal-initramfs" + +INITRD_LIVE ?= "${@ ('${DEPLOY_DIR_IMAGE}/' + d.getVar('INITRD_IMAGE') + '-${MACHINE}.cpio.gz') if d.getVar('INITRD_IMAGE') else ''}" + +UKI_CONFIG_FILE ?= "${WORKDIR}/core-image-minimal-uki.conf" +UKI_FILENAME ?= "${@ 'UKI.signed.efi' if d.getVar('UKI_CONFIG_FILE') else 'UKI.unsigned.efi'}" + +do_uki[depends] += " \ + systemd-boot:do_deploy \ + virtual/kernel:do_deploy \ + " + +# INITRD_IMAGE is added to INITRD_LIVE, which we use to create our initrd, so depend on it if it is set +# So we want to generate the initrd image if INITRD_IMAGE exists +do_uki[depends] += "${@ '${INITRD_IMAGE}:do_image_complete' if d.getVar('INITRD_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 subprocess + + # Construct the ukify command + ukify_cmd = ("ukify build") + + # Handle the creation of an initrd image by reading and concatenating multiple cpio files. + # If the INITRD_LIVE variable is defined and not empty, it opens the necessary files, reads their contents, + # and constructs a list. + if d.getVar('INITRD_LIVE'): + initrd_list = "" + for cpio in d.getVar('INITRD_LIVE').split(): + # get a list of initrds + initrd_list += cpio + ' ' + + ukify_cmd += " --initrd=%s" % initrd_list + else: + bb.fatal("ERROR - Required argument: INITRD") + + 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") + + # Architecture + target_arch = d.getVar('EFI_ARCH') + ukify_cmd += " --efi-arch %s" % target_arch + + # Stub + stub = "%s/linux%s.efi.stub" % (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'): + first_dtb = d.getVar('KERNEL_DEVICETREE').split()[0] + dtb_path = "%s/%s" % (deploy_dir_image, first_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 to sign the UKI. + if os.path.exists(d.getVar('UKI_CONFIG_FILE')): + ukify_cmd += " --config=%s" % d.getVar('UKI_CONFIG_FILE') + ukify_cmd += " --tools=%s%s/lib/systemd/tools" % (d.getVar("RECIPE_SYSROOT_NATIVE"), d.getVar("prefix")) + bb.note("Pulling keys from config file") + else: + bb.note("Generating unsigned UKI") + + # Custom UKI name + output = " --output=%s" % d.getVar('UKI_FILENAME') + ukify_cmd += " %s" % output + + # Set env to determine where bitbake should look for dynamic libraries + env = os.environ.copy() # get the env variables + env['LD_LIBRARY_PATH'] = d.expand("${RECIPE_SYSROOT_NATIVE}/usr/lib/systemd:${LD_LIBRARY_PATH}") + + # Run the ukify command + subprocess.check_call(ukify_cmd, env=env, shell=True) +} + +inherit deploy + +do_deploy () { + # Copy generated UKI into DEPLOYDIR + install ${B}/${UKI_FILENAME} ${DEPLOYDIR} +} + +addtask uki before do_deploy do_image after do_rootfs +addtask deploy before do_build after do_compile \ No newline at end of file diff --git a/meta/recipes-core/systemd/systemd_254.bb b/meta/recipes-core/systemd/systemd_254.bb index 8d5cf13095..65f132abb8 100644 --- a/meta/recipes-core/systemd/systemd_254.bb +++ b/meta/recipes-core/systemd/systemd_254.bb @@ -6,6 +6,9 @@ PE = "1" DEPENDS = "intltool-native gperf-native libcap util-linux python3-jinja2-native" +# The Ukify tool requires this module +DEPENDS:append:class-native = " python3-pefile-native" + SECTION = "base/shell" inherit useradd pkgconfig meson perlnative update-rc.d update-alternatives qemu systemd gettext bash-completion manpages features_check @@ -18,6 +21,8 @@ REQUIRED_DISTRO_FEATURES += "usrmerge" # that we don't build both udev and systemd in world builds. REQUIRED_DISTRO_FEATURES += "systemd" +REQUIRED_DISTRO_FEATURES:class-native = "" + SRC_URI += " \ file://touchscreen.rules \ file://00-create-volatile.conf \ @@ -120,6 +125,8 @@ PACKAGECONFIG:remove:libc-musl = " \ # https://github.com/seccomp/libseccomp/issues/347 PACKAGECONFIG:remove:mipsarch = "seccomp" +PACKAGECONFIG:class-native = "serial-getty-generator openssl tpm2 efi" + TARGET_CC_ARCH:append:libc-musl = " -D__UAPI_DEF_ETHHDR=0 -D_LARGEFILE64_SOURCE" # Some of the dependencies are weak-style recommends - if not available at runtime, @@ -260,6 +267,9 @@ EXTRA_OEMESON += "-Dkexec-path=${sbindir}/kexec \ -Dloadkeys-path=${bindir}/loadkeys \ -Dsetfont-path=${bindir}/setfont" +EXTRA_OEMESON:append:class-native = " -Dbootloader=true \ + -Dman=false \ + " # The 60 seconds is watchdog's default vaule. WATCHDOG_TIMEOUT ??= "60" @@ -380,6 +390,14 @@ do_install() { fi } +do_install:class-native() { + meson_do_install + install -d ${D}${bindir} + install -m 0755 ${S}/src/ukify/ukify.py ${D}${bindir}/ukify + install -d ${D}${prefix}/lib/systemd/tools + install -m 0755 ${B}/systemd-measure ${D}${prefix}/lib/systemd/tools +} + python populate_packages:prepend (){ systemdlibdir = d.getVar("rootlibdir") do_split_packages(d, systemdlibdir, r'^lib(.*)\.so\.*', 'lib%s', 'Systemd %s library', extra_depends='', allow_links=True) @@ -702,6 +720,9 @@ RRECOMMENDS:${PN} += "systemd-extra-utils \ ${@bb.utils.contains('PACKAGECONFIG', 'logind', 'pam-plugin-umask', '', d)} \ " +RRECOMMENDS:${PN}:class-native = "" +RDEPENDS:${PN}:class-native = "" + INSANE_SKIP:${PN} += "dev-so libdir" INSANE_SKIP:${PN}-dbg += "libdir" INSANE_SKIP:${PN}-doc += " libdir" @@ -852,3 +873,5 @@ pkg_postinst:udev-hwdb () { pkg_prerm:udev-hwdb () { rm -f $D${sysconfdir}/udev/hwdb.bin } + +BBCLASSEXTEND += "native" -- 2.34.1
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#187017): https://lists.openembedded.org/g/openembedded-core/message/187017 Mute This Topic: https://lists.openembedded.org/mt/101106095/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
