On Sat, 2 Sept 2023 at 02:32, Michelle Lin <michelle.lint...@gmail.com> wrote: > > 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 <michelle.lint...@gmail.com> > --- > 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
Hmm, I have not noticed this before. This doesn't look generic enough. KERNEL_DEVICETREE can have several DT files and the first one is not in any way special. It should not be picked up for the UKI image. E.g. in our (meta-qcom / qcom-armv8a) case the KERNEL_DEVICETREE lists dtb for all supported machines, ranging from the old dragonboard410c up to the latest HDKs. > + > + # 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 > > > > -- With best wishes Dmitry
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#191364): https://lists.openembedded.org/g/openembedded-core/message/191364 Mute This Topic: https://lists.openembedded.org/mt/101106095/21656 Group Owner: openembedded-core+ow...@lists.openembedded.org Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-