From: Mikko Rapeli <mikko.rapeli@linaro.org>
To: Dmitry Baryshkov <dbaryshkov@gmail.com>
Cc: Michelle Lin <michelle.linto91@gmail.com>,
openembedded-core@lists.openembedded.org
Subject: Re: [OE-core] [PATCH] uki: Add support for building Unified Kernel Images
Date: Tue, 28 Nov 2023 14:51:57 +0200 [thread overview]
Message-ID: <ZWXibQvpZls3Cg_g@nuoska> (raw)
In-Reply-To: <CALT56yM7fL9sSqW-mO64BoHz=SrJi8aOHCQqqbe64b+vpSSijw@mail.gmail.com>
Hi,
On Tue, Nov 28, 2023 at 02:32:14PM +0200, Dmitry Baryshkov wrote:
> On Sat, 2 Sept 2023 at 02:32, Michelle Lin <michelle.linto91@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.linto91@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.
So all decice tree files should be looped in. I hope ukify.py supports
this but IMO it should.
Cheers,
-Mikko
> > +
> > + # 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/7159507
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [mikko.rapeli@linaro.org]
> -=-=-=-=-=-=-=-=-=-=-=-
>
next prev parent reply other threads:[~2023-11-28 12:52 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-01 23:32 [PATCH] uki: Add support for building Unified Kernel Images Michelle Lin
2023-09-02 1:04 ` [OE-core] " Alejandro Enedino Hernandez Samaniego
2023-09-02 6:53 ` Richard Purdie
2023-09-06 22:29 ` Alejandro Enedino Hernandez Samaniego
2023-11-20 12:48 ` Dmitry Baryshkov
2023-11-20 13:26 ` Bruce Ashfield
2023-11-22 1:06 ` Dmitry Baryshkov
2023-11-21 14:44 ` Erik Schilling
2023-11-22 1:09 ` Dmitry Baryshkov
2023-09-04 6:23 ` Mikko Rapeli
2023-11-16 11:01 ` Erik Schilling
2023-11-28 12:32 ` Dmitry Baryshkov
2023-11-28 12:51 ` Mikko Rapeli [this message]
2023-11-28 13:08 ` Dmitry Baryshkov
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=ZWXibQvpZls3Cg_g@nuoska \
--to=mikko.rapeli@linaro.org \
--cc=dbaryshkov@gmail.com \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox