From 816de4c7b4ffc4ff07076c83c5fe7a67b39c5f9a Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Sat, 21 Jun 2025 22:46:29 +0200 Subject: [PATCH] classes: add discoverable disk image class Add a class to build discoverable disk images [1] through systemd-repart(-native). Note that systemd >= 256 is required for '--private-key-source' The class was adapted from a patch [2] floating upstream. Link: [1]: https://uapi-group.org/specifications/specs/discoverable_disk_image/ Link: [2]: https://lists.openembedded.org/g/openembedded-core/message/198724 Signed-off-by: Johannes Schneider Signed-off-by: Khem Raj --- .../classes/discoverable-disk-image.bbclass | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 meta-oe/classes/discoverable-disk-image.bbclass diff --git a/meta-oe/classes/discoverable-disk-image.bbclass b/meta-oe/classes/discoverable-disk-image.bbclass new file mode 100644 index 0000000000..1f3a7b08e1 --- /dev/null +++ b/meta-oe/classes/discoverable-disk-image.bbclass @@ -0,0 +1,137 @@ +## +# Copyright OpenEmbedded Contributors +# +# SPDX-License-Identifier: MIT +# +# +# Discoverable Disk Image (DDI) +# +# "DDIs (Discoverable Disk Images) are self-describing file system +# images that follow the DPS ( Discoverable Partitions Specification), +# wrapped in a GPT partition table, that may contain root (or /usr/) +# filesystems for bootable OS images, system extensions, configuration +# extensions, portable services, containers and more, and shall be +# protected by signed dm-verity all combined into one. They are +# designed to be composable and stackable, and provide security by +# default." +# https://uapi-group.org/specifications/specs/discoverable_disk_image/ +# https://uapi-group.org/specifications/specs/discoverable_partitions_specification/ +# https://www.freedesktop.org/software/systemd/man/latest/systemd.image-policy.html + +# To be able to use discoverable-disk-images with a +# root-verity-sig or usr-verity-sig configuration: +# - systemd needs to include the PACKAGECONFIG 'cryptsetup', and +# - the kernel needs the following features enabled: +# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y +# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING=y +# CONFIG_EROFS_FS=y +# CONFIG_EROFS_FS_XATTR=y +# CONFIG_EROFS_FS_ZIP=y +# CONFIG_EROFS_FS_ZIP_LZMA=y +# CONFIG_INTEGRITY_SIGNATURE=y +# CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y +# CONFIG_INTEGRITY_PLATFORM_KEYRING=y +# CONFIG_SYSTEM_BLACKLIST_KEYRING=y +# CONFIG_SYSTEM_BLACKLIST_HASH_LIST="" +# CONFIG_SIGNATURE=y + +# To sign DDIs, a key and certificate need to be provided by setting +# the variables: +# REPART_PRIVATE_KEY +# private key so sign the verity-hash +# REPART_PRIVATE_KEY_SOURCE +# optional, can be "engine:pkcs11" when using a (soft)hsm +# REPART_CERTIFICATE +# corresponding public certificate, in .pem format +# + +# For signature verification, systemd-sysext expects the matching +# certificate to reside in /etc/verity.d as PEM formated .crt file. +# +# To enforce loading of only signed extension images, an appropriate +# image policy has to be passed to systemd-sysext, e.g.: +# systemd-sysext --image-policy='root=signed+absent:usr=signed+absent:=unused+absent' merge + +# 'systemd-dissect' can be used to inspect, manually mount, ... a DDI. + +inherit image + +IMAGE_FSTYPES = "ddi" + +DEPENDS += " \ + systemd-repart-native \ + erofs-utils-native \ + openssl-native \ +" + +# systemd-repart --make-ddi takes one of "sysext", "confext" or "portable", +# which it then takes and looks up definitions in the host os; which we need +# to divert to the sysroot-native by setting '--definitions=' instead. +# The chosen DDI_TYPE influences which parts of the rootfs are copied into +# the ddi by systemd-repart: +# sysext: /usr (and if it exists: /opt) +# confext: /etc +# portable: / +# For details see systemd/repart/definitions/${REPART_DDI_TYPE}.repart.d/* +REPART_DDI_TYPE ?= "sysext" + +REPART_DDI_EXTENSION ?= "ddi" + +# systemd-repart creates temporary directoryies under /var/tmp/.#repartXXXXXXX/, +# to estimate partition size etc. Since files are copied there from the image/rootfs +# folder - which are owned by pseudo-root - this temporary location has to be +# added to the directories handled by pseudo; otherwise calls to e.g. +# fchown(0,0) inside systemd git/src/shared/copy.c end up failing. +PSEUDO_INCLUDE_PATHS .= ",/var/tmp/" + +oe_image_systemd_repart_make_ddi() { + + local additional_args="" + + if [ -n "${REPART_PRIVATE_KEY}" ] + then + if [ -n "${REPART_PRIVATE_KEY_SOURCE}" ] + then + additional_args="$additional_args --private-key-source=${REPART_PRIVATE_KEY_SOURCE}" + fi + additional_args="$additional_args --private-key=${REPART_PRIVATE_KEY}" + fi + + if [ -n "${REPART_CERTIFICATE}" ] + then + additional_args="$additional_args --certificate=${REPART_CERTIFICATE}" + fi + + # map architectures to systemd's expected values + local systemd_arch="${TARGET_ARCH}" + case "${systemd_arch}" in + aarch64) + systemd_arch=arm64 + ;; + x86_64) + systemd_arch=x86-64 + ;; + esac + + # prepare system-repart configuration + mkdir -p ${B}/definitions.repart.d + cp ${STAGING_LIBDIR_NATIVE}/systemd/repart/definitions/${REPART_DDI_TYPE}.repart.d/* ${B}/definitions.repart.d/ + # enable erofs compression + sed -i "/^Compression/d" ${B}/definitions.repart.d/10-root.conf + echo "Compression=lzma\nCompressionLevel=3" >> ${B}/definitions.repart.d/10-root.conf + # disable verity signature partition creation, if no key is provided + if [ -z "${REPART_PRIVATE_KEY}" ]; then + rm ${B}/definitions.repart.d/30-root-verity-sig.conf + fi + + systemd-repart \ + --definitions="${B}/definitions.repart.d/" \ + --copy-source="${IMAGE_ROOTFS}" \ + --empty=create --size=auto --dry-run=no --offline=yes \ + --architecture="${systemd_arch}" \ + --json=pretty --no-pager $additional_args \ + "${IMGDEPLOYDIR}/${IMAGE_NAME}${IMAGE_NAME_SUFFIX}.${REPART_DDI_EXTENSION}" +} + +IMAGE_CMD:ddi = "oe_image_systemd_repart_make_ddi" +do_image_ddi[deptask] += "do_unpack"