From: Emanuele Giuseppe Esposito <eesposit@xxxxxxxxxx> redhat/kernel.spec: add uki_addons to create UKI kernel cmdline addons Upstream Status: RHEL-Only By defininig an addon in uki_cmdline_addons.conf, the script uki_addons.py will automatically create an UKI addon to be shipped together in the same package. For additional info on how to format uki_cmdline_addons.conf, check uki_addons.py head comment. 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 @@ -690,6 +690,7 @@ sources-rh: $(TARBALL) generate-testpatch-tmp setup-source dist-configs-check 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 \ @@ -698,6 +699,7 @@ sources-rh: $(TARBALL) generate-testpatch-tmp setup-source dist-configs-check README.rst \ kernel-local \ dracut-virt.conf \ + uki_cmdline_addons.conf \ $(SOURCES)/ @cat $$(ls -1 $(SPECPACKAGE_NAME).changelog-* | sort -t '.' -k 3 -n -r) \ > $(SOURCES)/kernel.changelog 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: uki_cmdline_addons.conf + Source100: rheldup3.x509 Source101: rhelkpatch1.x509 @@ -2537,6 +2542,15 @@ BuildKernel() { fi mv $KernelUnifiedImage.signed $KernelUnifiedImage + KernelAddonsDir="$KernelUnifiedImageDir/addons" + mkdir -p $KernelAddonsDir + python3 %{SOURCE151} %{SOURCE152} $KernelAddonsDir + for addon in "$KernelAddonsDir"/*; 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 @@ -3692,6 +3706,7 @@ fi\ /lib/modules/%{KVERREL}%{?3:+%{3}}/config\ /lib/modules/%{KVERREL}%{?3:+%{3}}/modules.builtin*\ %attr(0644, root, root) /lib/modules/%{KVERREL}%{?3:+%{3}}/%{?-k:%{-k*}}%{!?-k:vmlinuz}-virt.efi\ +/lib/modules/%{KVERREL}%{?3:+%{3}}/addons/*.addon.efi\ %ghost /%{image_install_path}/efi/EFI/Linux/%{?-k:%{-k*}}%{!?-k:*}-%{KVERREL}%{?3:+%{3}}.efi\ %endif\ %endif\ 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,137 @@ +#!/bin/bash +# +# This script reads a given uki addons config file list, and creates an addon +# for each definition given. +# +# Usage: python uki_addons.py cfgfile cert.pem key output_dir +# +# This tool requires the systemd-ukify and systemd-boot yum packages. +# +# Cfgfile definition +#------------------- +# Each addon is separate from the next by an empty line. +# Each addon has 3 mandatory fields, plus one optional (sbat). +# Each field (except the fourth) is terminated by a single newline. +# No multiline fields! If a cmdline starts to be too long, maybe it's time to +# create multiple addons. +# +# Cfgfile fields +#--------------- +# - Name: name of the addon. This tool will create an addon called <name>.addon.efi +# and put it in @output_dir. Name might or might not contain .addon.efi. +# If it is missing, it will be added automatically. +# - Description: human readable description of the addon. Not included in the +# generated file. +# - Command line: the command line to be inserted into the addon. +# - SBAT (optional): If this field is specified, replace .sbat with the provided +# one. This field can be multiline, but must have an additional +# newline (or EOF) to separate from the next addon. + +import os +import sys +import collections +import subprocess + +SYSTEMD_STUB_PATH = '/usr/lib/systemd/boot/efi/addonx64.efi.stub' +UKIFY_PATH = '/usr/lib/systemd/ukify' + +def usage(err): + print(f'Usage: {os.path.basename(__file__)} cfgfile cert.pem key output_dir') + if err: + print(f'Error:{err}') + sys.exit(1) + +def cfgfile_fields_help(): + print("Cfgfile fields") + print("---------------") + print(" - Name: name of the addon. This tool will create an addon called <name>.addon.efi") + print(" and put it in @output_dir. Name might or might not contain .addon.efi.") + print(" If it is missing, it will be added automatically.") + print(" - Description: human readable description of the addon. Not included in the") + print(" generated file.") + print(" - Command line: the command line to be inserted into the addon.") + print(" - SBAT (optional): If this field is specified, replace .sbat with the provided") + print(" one. This field can be multiline, but must have an additional") + print(" newline (or EOF) to separate from the next addon.") + sys.exit(1) + +def check_arguments(cfgfile, output): + if not os.path.isfile(cfgfile): + usage(f'cfgfile {cfgfile} is not a file, or does not exist!') + + if not os.path.isdir(output): + usage(f'output_dir {output} is not a dir, or does not exist!') + +UKICmdlineAddon = collections.namedtuple('UKICmdlineAddon', ['name', 'desc', 'cmdline', 'sbat']) + +def create_uki_addon(start, end, lines): + name = lines[start].rstrip() + if not name.endswith('.addon.efi'): + name += '.addon.efi' + desc = lines[start + 1].rstrip() + cmdline = lines[start + 2].rstrip() + sbat = ''.join(lines[start+3:end]) + return UKICmdlineAddon(name, desc, cmdline, sbat) + +def parse_addon(i, lines): + start = -1 + while i < len(lines) and start < 0: + if lines[i] != '\n': + start = i + i += 1 + + end = -1 + while i < len(lines) and end < 0: + if lines[i] == '\n': + end = i + i += 1 + if i == len(lines) and end < 0: + end = i + + if start < 0 or end < 0: + return None, i + + if start + 3 > end: # too small, fields ignored + print(f'Addon line {start+1}:{end} ignored, must contain at least name-descr-cmdline') + return None, i + + return create_uki_addon(start, end, lines), i + +def main(cfgfile, output): + if not output.endswith('/'): + output += '/' + + with open(cfgfile, 'r') as addons: + lines = addons.readlines() + + i = 0 + while i < len(lines): + addon, i = parse_addon(i, lines) + if not addon: + continue + out_path = output + addon.name + cmd = [ + f'{UKIFY_PATH}', 'build', + f'--stub={SYSTEMD_STUB_PATH}', + f'--cmdline="{addon.cmdline}"', + f'--output={out_path}'] + if addon.sbat != '': + cmd.append('--sbat=' + addon.sbat.rstrip() +'') + + # print(''.join(cmd)) + print(cmd) + print() + subprocess.check_call(cmd, text=True) + +if __name__ == "__main__": + argc = len(sys.argv) - 1 + if argc != 2: + usage('too few or too many parameters!') + + cfgfile = sys.argv[1] + output = sys.argv[2] + + check_arguments(cfgfile, output) + main(cfgfile, output) + + diff --git a/redhat/uki_cmdline_addons.conf b/redhat/uki_cmdline_addons.conf new file mode 100644 index blahblah..blahblah 100644 --- /dev/null +++ b/redhat/uki_cmdline_addons.conf -- 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