All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] uki: Add support for building Unified Kernel Images
@ 2023-09-01 23:32 Michelle Lin
  2023-09-02  1:04 ` [OE-core] " Alejandro Enedino Hernandez Samaniego
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Michelle Lin @ 2023-09-01 23:32 UTC (permalink / raw)
  To: openembedded-core; +Cc: Michelle Lin

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"
+
 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



^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2023-11-28 13:09 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
2023-11-28 13:08     ` Dmitry Baryshkov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.