diff options
author | Luca Boccassi <bluca@debian.org> | 2023-04-18 00:40:43 +0100 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2023-04-26 16:55:26 +0200 |
commit | 00e5933f57c6e336ebed18601299acc6855bb3c2 (patch) | |
tree | b73418bc498c7864478a9177d77a7114c73ef609 | |
parent | 1db4acbe5d78a6337ffb163d9bd12eabac2fdda4 (diff) | |
download | systemd-00e5933f57c6e336ebed18601299acc6855bb3c2.tar.gz |
ukify: allow building PE addon
Make the kernel optional too, so that we can easily build and sign a PE addon,
that can be used to carry extra command line options.
-rw-r--r-- | man/ukify.xml | 33 | ||||
-rwxr-xr-x | src/ukify/test/test_ukify.py | 21 | ||||
-rwxr-xr-x | src/ukify/ukify.py | 17 |
3 files changed, 56 insertions, 15 deletions
diff --git a/man/ukify.xml b/man/ukify.xml index c3c0d3f2df..97c3f899c7 100644 --- a/man/ukify.xml +++ b/man/ukify.xml @@ -17,14 +17,14 @@ <refnamediv> <refname>ukify</refname> - <refpurpose>Combine kernel and initrd into a signed Unified Kernel Image</refpurpose> + <refpurpose>Combine components into a signed Unified Kernel Image for UEFI systems</refpurpose> </refnamediv> <refsynopsisdiv> <cmdsynopsis> <command>/usr/lib/systemd/ukify</command> - <arg choice="plain"><replaceable>LINUX</replaceable></arg> - <arg choice="plain" rep="repeat"><replaceable>INITRD</replaceable></arg> + <arg choice="opt"><replaceable>LINUX</replaceable></arg> + <arg choice="opt" rep="repeat"><replaceable>INITRD</replaceable></arg> <arg choice="opt" rep="repeat">OPTIONS</arg> </cmdsynopsis> </refsynopsisdiv> @@ -35,8 +35,8 @@ <para>Note: this command is experimental for now. While it is intended to become a regular component of systemd, it might still change in behaviour and interface.</para> - <para><command>ukify</command> is a tool that combines a kernel and an initrd with - a UEFI boot stub to create a + <para><command>ukify</command> is a tool that combines components (e.g.: a kernel and an initrd with + a UEFI boot stub) to create a <ulink url="https://uapi-group.org/specifications/specs/unified_kernel_image/">Unified Kernel Image (UKI)</ulink> — a PE binary that can be executed by the firmware to start the embedded linux kernel. See <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> @@ -53,6 +53,9 @@ and <option>--section=</option> below.</para> + <para><command>ukify</command> can also be used to assemble a PE binary that is not executable but + contains auxiliary data, for example additional kernel command line entries.</para> + <para>If PCR signing keys are provided via the <option>--pcr-public-key=</option> and <option>--pcr-private-key=</option> options, PCR values that will be seen after booting with the given kernel, initrd, and other sections, will be calculated, signed, and embedded in the UKI. @@ -78,10 +81,9 @@ <refsect1> <title>Options</title> - <para>Note that the <replaceable>LINUX</replaceable> positional argument is mandatory. The - <replaceable>INITRD</replaceable> positional arguments are optional. If more than one is specified, they - will all be combined into a single PE section. This is useful to for example prepend microcode before the - actual initrd.</para> + <para>The <replaceable>LINUX</replaceable> and <replaceable>INITRD</replaceable> positional arguments are + optional. If more than one <replaceable>INITRD</replaceable> are specified, they will all be combined into + a single PE section. This is useful to for example prepend microcode before the actual initrd.</para> <para>The following options are understood:</para> @@ -296,6 +298,19 @@ key <filename index='false'>pcr-private-system-key.pem</filename>. The Linux binary and the resulting combined image will be signed with the SecureBoot key <filename index='false'>sb.key</filename>.</para> </example> + + <example> + <title>Kernel command line auxiliary PE</title> + + <programlisting>ukify \ + --secureboot-private-key=sb.key \ + --secureboot-certificate=sb.cert \ + --cmdline='debug' \ + --output=debug.cmdline.efi + </programlisting> + + <para>This creates a signed PE binary that contains an additional kernel command line parameter.</para> + </example> </refsect1> <refsect1> diff --git a/src/ukify/test/test_ukify.py b/src/ukify/test/test_ukify.py index 7e025b5ef4..1b58f05d4c 100755 --- a/src/ukify/test/test_ukify.py +++ b/src/ukify/test/test_ukify.py @@ -206,6 +206,27 @@ def test_sections(kernel_initrd, tmpdir): for sect in 'text osrel cmdline linux initrd uname test'.split(): assert re.search(fr'^\s*\d+\s+.{sect}\s+0', dump, re.MULTILINE) +def test_addon(kernel_initrd, tmpdir): + output = f'{tmpdir}/addon.efi' + opts = ukify.parse_args([ + f'--output={output}', + '--cmdline=ARG1 ARG2 ARG3', + '--section=.test:CONTENTZ', + ]) + + try: + ukify.check_inputs(opts) + except OSError as e: + pytest.skip(str(e)) + + ukify.make_uki(opts) + + # let's check that objdump likes the resulting file + dump = subprocess.check_output(['objdump', '-h', output], text=True) + + for sect in 'text cmdline test'.split(): + assert re.search(fr'^\s*\d+\s+.{sect}\s+0', dump, re.MULTILINE) + def unbase64(filename): tmp = tempfile.NamedTemporaryFile() diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index b319f2dc91..3fbeb2b215 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -551,7 +551,7 @@ def make_uki(opts): sbsign_invocation += ['--engine', opts.signing_engine] sign_kernel = opts.sign_kernel - if sign_kernel is None and opts.sb_key: + if sign_kernel is None and opts.linux is not None and opts.sb_key: # figure out if we should sign the kernel sbverify_tool = find_tool('sbverify', opts=opts) @@ -583,7 +583,7 @@ def make_uki(opts): else: linux = opts.linux - if opts.uname is None: + if opts.uname is None and opts.linux is not None: print('Kernel version not specified, starting autodetection 😖.') opts.uname = Uname.scrape(opts.linux, opts=opts) @@ -624,7 +624,8 @@ def make_uki(opts): # UKI creation - uki.add_section(Section.create('.linux', linux, measure=True)) + if linux is not None: + uki.add_section(Section.create('.linux', linux, measure=True)) if opts.sb_key: unsigned = tempfile.NamedTemporaryFile(prefix='uki') @@ -657,7 +658,7 @@ def parse_args(args=None): description='Build and sign Unified Kernel Images', allow_abbrev=False, usage='''\ -usage: ukify [options…] linux initrd… +usage: ukify [options…] [linux [initrd…]] ukify -h | --help ''') @@ -666,6 +667,7 @@ usage: ukify [options…] linux initrd… p.add_argument('linux', type=pathlib.Path, + nargs="?", help='vmlinuz file [.linux section]') p.add_argument('initrd', type=pathlib.Path, @@ -769,7 +771,8 @@ usage: ukify [options…] linux initrd… opts = p.parse_args(args) - path_is_readable(opts.linux) + if opts.linux is not None: + path_is_readable(opts.linux) for initrd in opts.initrd or (): path_is_readable(initrd) path_is_readable(opts.devicetree) @@ -784,7 +787,7 @@ usage: ukify [options…] linux initrd… if opts.os_release is not None and opts.os_release.startswith('@'): opts.os_release = path_is_readable(opts.os_release[1:]) - elif opts.os_release is None: + elif opts.os_release is None and opts.linux is not None: p = pathlib.Path('/etc/os-release') if not p.exists(): p = path_is_readable('/usr/lib/os-release') @@ -815,6 +818,8 @@ usage: ukify [options…] linux initrd… raise ValueError('--phases= specifications must match --pcr-private-key=') if opts.output is None: + if opts.linux is None: + raise ValueError('--output= must be specified when building a PE addon') suffix = '.efi' if opts.sb_key else '.unsigned.efi' opts.output = opts.linux.name + suffix |