From: Emanuele Giuseppe Esposito <eesposit@xxxxxxxxxx> redhat/kernel.spec: add uki_addons to create UKI kernel cmdline addons Upstream Status: RHEL-Only The folder redhat/addons will contain all addons configs specifying the UKI kernel cmdline addons to be created in the next build. An addon config is simply a .addon plain text file, where any line is taken as kernel cmdline, except for the ones starting with '#', which will be automatically ignored. redhat/scripts/uki_addons.py will take care of parsing all configs and folders in redhat/addons and call 'ukify' to create the actual addons. The output addon filename will be a concatenation of all folders in redhat/addons that are part of the addon config path. The folder hierarchy inside of redhat/addons is similar to redhat/configs: $distro/$UKI_NAME/%arch. It is also possible to add .sbat to all the generated addons, by populating redhat/addons/$distro/$UKI_NAME/%arch/sbat/sbat.conf. Syntax is same as the addons config. At build time, Makefile will create a tar.gz archive ($distro-$UKI_NAME-addons.tar.gz) containing all the files in redhat/addons/$distro/$UKI_NAME. It will then passed to the kernel specfile that will extract the addons from it and generate the UKI kernel cmdline addons. Signed-off-by: Emanuele Giuseppe Esposito <eesposit@xxxxxxxxxx> diff --git a/redhat/Makefile b/redhat/Makefile index blahblah..blahblah 100644 --- a/redhat/Makefile +++ b/redhat/Makefile @@ -685,6 +685,13 @@ sources-rh: $(TARBALL) $(KABI_TARBALL) $(KABIDW_TARBALL) generate-testpatch-tmp @sed -e "s/%%SPECKVERSION%%/$(SPECKVERSION)/" \ -e "s/%%SPECKPATCHLEVEL%%/$(SPECKPATCHLEVEL)/" \ scripts/gating/rpminspect.yaml > $(SOURCES)/rpminspect.yaml + @for UKI_FLAVOR in addons/*; do \ + FLAVOR_NAME=$$(basename $$UKI_FLAVOR); \ + for UKI in $$UKI_FLAVOR/*; do \ + UKI_NAME=$$(basename $$UKI); \ + tar -czf $$FLAVOR_NAME-$$UKI_NAME-addons.tar.gz $$UKI; \ + done; \ + done @cp scripts/kernel-tools/kvm_stat.logrotate \ keys/rhel*.x509 \ keys/nvidia*.x509 \ @@ -697,6 +704,7 @@ sources-rh: $(TARBALL) $(KABI_TARBALL) $(KABIDW_TARBALL) generate-testpatch-tmp scripts/mod/mod-partner.list \ scripts/mod/mod-sign.sh \ scripts/mod/mod-kvm.list \ + scripts/uki_addons.py \ configs/flavors \ configs/generate_all_configs.sh \ configs/merge.py \ @@ -705,6 +713,7 @@ sources-rh: $(TARBALL) $(KABI_TARBALL) $(KABIDW_TARBALL) generate-testpatch-tmp README.rst \ kernel-local \ dracut-virt.conf \ + *-addons.tar.gz \ $(SOURCES)/ @cat $$(ls -1 $(SPECPACKAGE_NAME).changelog-* | sort -t '.' -k 3 -n -r) \ > $(SOURCES)/kernel.changelog diff --git a/redhat/addons/fedora/virt/aarch64/sbat/.gitkeep b/redhat/addons/fedora/virt/aarch64/sbat/.gitkeep new file mode 100644 index blahblah..blahblah 100644 --- /dev/null +++ b/redhat/addons/fedora/virt/aarch64/sbat/.gitkeep diff --git a/redhat/addons/rhel/virt/aarch64/sbat/.gitkeep b/redhat/addons/rhel/virt/aarch64/sbat/.gitkeep new file mode 100644 index blahblah..blahblah 100644 --- /dev/null +++ b/redhat/addons/rhel/virt/aarch64/sbat/.gitkeep diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template index blahblah..blahblah 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template @@ -792,6 +792,8 @@ BuildRequires: binutils BuildRequires: lvm2 BuildRequires: systemd-boot-unsigned # For systemd-stub and systemd-pcrphase +BuildRequires: systemd-ukify +# For UKI kernel cmdline addons BuildRequires: systemd-udev >= 252-1 # For TPM operations in UKI initramfs BuildRequires: tpm2-tools @@ -933,6 +935,9 @@ Source86: dracut-virt.conf Source87: flavors +Source151: uki_addons.py +Source152: %{primary_target}-virt-addons.tar.gz + Source100: rheldup3.x509 Source101: rhelkpatch1.x509 Source102: nvidiagpuoot001.x509 @@ -1554,6 +1559,11 @@ Provides: kernel-%{?1:%{1}-}uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires: kernel%{?1:-%{1}}-modules-core-uname-r = %{KVERREL}%{uname_suffix %{?1:+%{1}}}\ Requires(pre): %{kernel_prereq}\ Requires(pre): systemd >= 254-1\ +%package %{?1:%{1}-}uki-virt-addons\ +Summary: %{variant_summary} unified kernel image addons for virtual machines\ +Provides: installonlypkg(kernel)\ +Requires: kernel%{?1:-%{1}}-uki-virt = %{specrpmversion}-%{release}\ +Requires(pre): systemd >= 254-1\ %endif\ %endif\ %if %{with_gcov}\ @@ -1693,31 +1703,49 @@ input and output, etc. %if %{with_up} && %{with_debug} && %{with_efiuki} %description debug-uki-virt Prebuilt debug unified kernel image for virtual machines. + +%description debug-uki-virt-addons +Prebuilt debug unified kernel image addons for virtual machines. %endif %if %{with_up_base} && %{with_efiuki} %description uki-virt Prebuilt default unified kernel image for virtual machines. + +%description uki-virt-addons +Prebuilt default unified kernel image addons for virtual machines. %endif %if %{with_arm64_16k} && %{with_debug} && %{with_efiuki} %description 16k-debug-uki-virt Prebuilt 16k debug unified kernel image for virtual machines. + +%description 16k-debug-uki-virt-addons +Prebuilt 16k debug unified kernel image addons for virtual machines. %endif %if %{with_arm64_16k_base} && %{with_efiuki} %description 16k-uki-virt Prebuilt 16k unified kernel image for virtual machines. + +%description 16k-uki-virt-addons +Prebuilt 16k unified kernel image addons for virtual machines. %endif %if %{with_arm64_64k} && %{with_debug} && %{with_efiuki} %description 64k-debug-uki-virt Prebuilt 64k debug unified kernel image for virtual machines. + +%description 64k-debug-uki-virt-addons +Prebuilt 64k debug unified kernel image addons for virtual machines. %endif %if %{with_arm64_64k_base} && %{with_efiuki} %description 64k-uki-virt Prebuilt 64k unified kernel image for virtual machines. + +%description 64k-uki-virt-addons +Prebuilt 64k unified kernel image addons for virtual machines. %endif %if %{with_ipaclones} @@ -2633,6 +2661,12 @@ BuildKernel() { --kernel-cmdline 'console=tty0 console=ttyS0' \ $KernelUnifiedImage + tar -xvf %{SOURCE152} -C $KernelUnifiedImageDir + KernelAddonsDir="$KernelUnifiedImageDir/addons/%{primary_target}/virt/%{_target_cpu}" + KernelAddonsDirOut="$RPM_BUILD_ROOT/usr/lib/linux/extra.d" + mkdir -p $KernelAddonsDirOut + python3 %{SOURCE151} $KernelAddonsDir $KernelAddonsDirOut %{_target_cpu} + %if %{signkernel} %{log_msg "Sign the EFI UKI kernel"} %pesign -s -i $KernelUnifiedImage -o $KernelUnifiedImage.tmp -a %{secureboot_ca_0} -c %{secureboot_key_0} -n %{pesign_name_0} @@ -2645,9 +2679,17 @@ BuildKernel() { fi mv $KernelUnifiedImage.signed $KernelUnifiedImage + for addon in "$KernelAddonsDirOut"/*; do + %pesign -s -i $addon -o $addon.signed -a %{secureboot_ca_1} -c %{secureboot_key_1} -n %{pesign_name_1} + rm -f $addon + mv $addon.signed $addon + done + # signkernel %endif + rm -rf $KernelUnifiedImageDir/addons + pushd $RPM_BUILD_ROOT # with_efiuki @@ -3887,6 +3929,8 @@ fi\ /lib/modules/%{KVERREL}%{?3:+%{3}}/modules.builtin*\ %attr(0644, root, root) /lib/modules/%{KVERREL}%{?3:+%{3}}/%{?-k:%{-k*}}%{!?-k:vmlinuz}-virt.efi\ %ghost /%{image_install_path}/efi/EFI/Linux/%{?-k:%{-k*}}%{!?-k:*}-%{KVERREL}%{?3:+%{3}}.efi\ +%{expand:%%files %{?3:%{3}-}uki-virt-addons}\ +/usr/lib/linux/extra.d/*.addon.efi\ %endif\ %endif\ %if %{?3:1} %{!?3:0}\ diff --git a/redhat/scripts/uki_addons.py b/redhat/scripts/uki_addons.py new file mode 100644 index blahblah..blahblah 100644 --- /dev/null +++ b/redhat/scripts/uki_addons.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# +# This script recursively inspects a given uki directory, and creates an addon +# for each file found. +# +# Usage: python uki_addons.py input_dir out_dir arch +# +# input_dir must be a path ending with this format: +# [..]/$distro/$uki_name/$arch/ +# +# This tool requires the systemd-ukify and systemd-boot packages. +# +# Addon file +#----------- +# Each addon terminates with .addon +# Each addon contains only two types of lines: +# Lines beginning with '#' are description and thus ignored +# All other lines are command line to be added. +# The name of the end resulting addon is taken from the folder hierarchy. +# For example, and addon in rhel/virt/x86_64/hello.addon will result in +# an UKI addon file generated in out_dir called hello-virt.rhel.x86_64.addon.efi +# +# sbat.conf +#---------- +# This file is containing the sbat string for *all* addons being created. +# This file is optional, but when used has to be put in out_dir/sbat/sbat.conf. +# It follows the same syntax as the addon files, meaning '#' is comment and +# the rest is taken as sbat string and feed to ukify. +# +# +# How to extend the script and kernel.spec with a new arch or uki or distro +#-------------------------------------------------------------------------- +# A new distro has to be added by creating the folder in redhat/addons. +# See above to how the directory hierarchy in redhat/addons is expected to be. +# After that, if the distro is a different arch from the one already supported, +# one needs to 1) extend the %define with_efiuki in kernel.spec.template and +# 2) define SYSTEMD_STUB_%arch as done below. +# If a new UKI has to be created with a different name from the existing ones, +# the logic to create the addons and call this script has to be implemented too +# in kernel.spec.template. As an example, see how the 'virt' UKI addons are +# created. + +import os +import sys +import collections +import subprocess + +SYSTEMD_STUB_PATH = '/usr/lib/systemd/boot/efi/' +SYSTEMD_STUB_x86_64 = 'addonx64.efi.stub' +SYSTEMD_STUB_aarch64 = 'addonaa64.efi.stub' +CURRENT_SYSTEMD_STUB = None # set in __main__ + +UKIFY_PATH = '/usr/lib/systemd/ukify' +SBAT_LOCATION = '/sbat/sbat.conf' + +def usage(err): + print(f'Usage: {os.path.basename(__file__)} input_dir output_dir arch') + print(f'Error:{err}') + sys.exit(1) + +def check_clean_arguments(in_dir, out_dir): + # Remove end '/' + if in_dir[-1:] == '/': + in_dir = in_dir[:-1] + if out_dir[-1:] == '/': + out_dir = out_dir[:-1] + if not os.path.isdir(in_dir): + usage(f'in_dir {in_dir} is not a dir, or does not exist!') + if not os.path.isdir(out_dir): + usage(f'out_dir_dir {out_dir} is not a dir, or does not exist!') + return in_dir, out_dir + +UKICmdlineAddon = collections.namedtuple('UKICmdlineAddon', ['name', 'cmdline']) +uki_addon_list = [] + +def parse_addon_conf(path, rstrip=True): + with open(path, 'r') as addons: + lines = addons.readlines() + cmdline = '' + for l in lines: + l = l.lstrip() + if not l: + continue + if l[0] == '#': + continue + if rstrip: + l = l.rstrip() + ' ' + cmdline += l + if cmdline == '': + return '' + return cmdline + +def parse_in_dir(in_dir): + for (dirpath, _, filenames) in os.walk(in_dir): + path = dirpath.split("/") + if len(path) < 3: + continue + arch = path[-1] + uki = path[-2] + distro = path[-3] + for addon_f in filenames: + if addon_f.endswith('.addon'): + addon_name = addon_f.replace(".addon","") + addon_full_name = f'{addon_name}-{uki}.{distro}.{arch}.addon.efi' + cmdline = parse_addon_conf(dirpath+'/'+addon_f) + if cmdline: + uki_addon_list.append(UKICmdlineAddon(addon_full_name, cmdline)) + +def parse_sbat(in_dir): + sbat_loc = in_dir + SBAT_LOCATION + if not os.path.isfile(sbat_loc): + return + return parse_addon_conf(sbat_loc, rstrip=False) + +def main(in_dir, out_dir): + sbat_string = parse_sbat(in_dir) + for uki_addon in uki_addon_list: + out_path = out_dir + '/' + uki_addon.name + cmd = [ + f'{UKIFY_PATH}', 'build', + f'--stub={CURRENT_SYSTEMD_STUB}', + f'--cmdline="{uki_addon.cmdline}"', + f'--output={out_path}'] + if sbat_string: + cmd.append('--sbat="' + sbat_string.rstrip() +'"') + + print(cmd) + subprocess.check_call(cmd, text=True) + +if __name__ == "__main__": + argc = len(sys.argv) - 1 + if argc != 3: + usage('too few or too many parameters!') + + in_dir = sys.argv[1] + out_dir = sys.argv[2] + arch = sys.argv[3] + if arch == 'x86_64': + stub_arc = SYSTEMD_STUB_x86_64 + elif arch == 'aarch64': + stub_arc = SYSTEMD_STUB_aarch64 + else: + usage(f'arch {arch} not recognized!') + CURRENT_SYSTEMD_STUB = SYSTEMD_STUB_PATH + stub_arc + + in_dir, out_dir = check_clean_arguments(in_dir, out_dir) + parse_in_dir(in_dir) + main(in_dir, out_dir) + + -- https://gitlab.com/cki-project/kernel-ark/-/merge_requests/2917 -- _______________________________________________ kernel mailing list -- kernel@xxxxxxxxxxxxxxxxxxxxxxx To unsubscribe send an email to kernel-leave@xxxxxxxxxxxxxxxxxxxxxxx Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedoraproject.org/archives/list/kernel@xxxxxxxxxxxxxxxxxxxxxxx Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue