From: Alejandro Enedino Hernandez Samaniego <alhe@linux.microsoft.com>
To: Richard Purdie <richard.purdie@linuxfoundation.org>,
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: Wed, 6 Sep 2023 16:29:23 -0600 [thread overview]
Message-ID: <6f267d3e-adc7-c650-8d81-4fc019384d5a@linux.microsoft.com> (raw)
In-Reply-To: <141c44bea4477d552aa4fc0371094b8ad4dc65b5.camel@linuxfoundation.org>
On 9/2/23 00:53, Richard Purdie wrote:
> On Fri, 2023-09-01 at 23:32 +0000, Michelle Lin 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
>> +
>> + # 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"
> Do we need to add this to OE-Core? I think this will cause current
> builds to fail?
I think you are right, there are some dependencies from this that are
not present in OE-core, this probably belongs in a different layer, at
least for the time being.
Alejandro
>
>> +
>> 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"
> We've long avoided a systemd-native recipe as the meaning can be easily
> confused and I'm not thrilled to be adding one now.
>
> Perhaps this should be as a separate systemd-tools-native recipe to
> make it clear this isn't full systemd?
>
> How much of systemd does this recipe compile?
>
> Cheers,
>
> Richard
>
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#187021): https://lists.openembedded.org/g/openembedded-core/message/187021
> Mute This Topic: https://lists.openembedded.org/mt/101106095/4354175
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [alhe@linux.microsoft.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
next prev parent reply other threads:[~2023-09-06 22:29 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 [this message]
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
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=6f267d3e-adc7-c650-8d81-4fc019384d5a@linux.microsoft.com \
--to=alhe@linux.microsoft.com \
--cc=michelle.linto91@gmail.com \
--cc=openembedded-core@lists.openembedded.org \
--cc=richard.purdie@linuxfoundation.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