summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/ukify.xml33
-rwxr-xr-xsrc/ukify/test/test_ukify.py21
-rwxr-xr-xsrc/ukify/ukify.py17
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