mirror of
https://github.com/systemd/systemd.git
synced 2024-12-29 15:22:07 +03:00
de7ad6d4f4
Let's grab another so far unused PCR, and measure all sysext images into
it that we load from the ESP. Note that this is possibly partly redundant,
since sysext images should have dm-verity enabled, and that is hooked up
to IMA. However, measuring this explicitly has the benefit that we can
measure filenames too, easily, and that all without need for IMA or
anything like that.
This means: when booting a unified sd-stub kernel through sd-boot we'll
now have:
1. PCR 11: unified kernel image payload (i.e. kernel, initrd, boot
splash, dtb, osrelease)
2. PCR 12: kernel command line (i.e. the one embedded in the image, plus
optionally an overriden one) + any credential files picked up by
sd-stub
3. PCR 13: sysext images picked up by sd-stub
And each of these three PCRs should carry just the above, and start from
zero, thus be pre-calculatable.
Thus, all components and parameters of the OS boot process (i.e.
everything after the boot loader) is now nicely pre-calculable.
NOTE: this actually replaces previous measuring of the syext images into
PCR 4. I added this back in 845707aae2
,
following the train of thought, that sysext images for the initrd should
be measured like the initrd itself they are for, and according to my
thinking that would be a unified kernel which is measured by firmware
into PCR 4 like any other UEFI executables.
However, I think we should depart from that idea. First and foremost
that makes it harder to pre-calculate PCR 4 (since we actually measured
quite incompatible records to the TPM event log), but also I think
there's great value in being able to write policies that bind to the
used sysexts independently of the earlier boot chain (i.e. shim, boot
loader, unified kernel), hence a separate PCR makes more sense.
Strictly speaking, this is a compatibility break, but I think one we can
get away with, simply because the initrd sysext images are currently not
picked up by systemd-sysext yet in the initrd, and because of that we
can be reasonably sure noone uses this yet, and hence relies on the PCR
register used. Hence, let's clean this up before people actually do
start relying on this.
332 lines
16 KiB
XML
332 lines
16 KiB
XML
<?xml version='1.0'?> <!--*-nxml-*-->
|
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
|
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
|
|
|
<refentry id="systemd-stub" conditional='HAVE_GNU_EFI'
|
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
<refentryinfo>
|
|
<title>systemd-stub</title>
|
|
<productname>systemd</productname>
|
|
</refentryinfo>
|
|
|
|
<refmeta>
|
|
<refentrytitle>systemd-stub</refentrytitle>
|
|
<manvolnum>7</manvolnum>
|
|
</refmeta>
|
|
|
|
<refnamediv>
|
|
<refname>systemd-stub</refname>
|
|
<refname>sd-stub</refname>
|
|
<refname>linuxx64.efi.stub</refname>
|
|
<refname>linuxia32.efi.stub</refname>
|
|
<refname>linuxaa64.efi.stub</refname>
|
|
<refpurpose>A simple UEFI kernel boot stub</refpurpose>
|
|
</refnamediv>
|
|
|
|
<refsynopsisdiv>
|
|
<para><filename>/usr/lib/systemd/boot/efi/linuxx64.efi.stub</filename></para>
|
|
<para><filename>/usr/lib/systemd/boot/efi/linuxia32.efi.stub</filename></para>
|
|
<para><filename>/usr/lib/systemd/boot/efi/linuxaa64.efi.stub</filename></para>
|
|
<para><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.cred</filename></para>
|
|
<para><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.raw</filename></para>
|
|
<para><filename><replaceable>ESP</replaceable>/loader/credentials/*.cred</filename></para>
|
|
</refsynopsisdiv>
|
|
|
|
<refsect1>
|
|
<title>Description</title>
|
|
|
|
<para><command>systemd-stub</command> (stored in per-architecture files
|
|
<filename>linuxx64.efi.stub</filename>, <filename>linuxia32.efi.stub</filename>,
|
|
<filename>linuxaa64.efi.stub</filename> on disk) is a simple UEFI boot stub. An UEFI boot stub is
|
|
attached to a Linux kernel binary image, and is a piece of code that runs in the UEFI firmware
|
|
environment before transitioning into the Linux kernel environment. The UEFI boot stub ensures a Linux
|
|
kernel is executable as regular UEFI binary, and is able to do various preparations before switching the
|
|
system into the Linux world.</para>
|
|
|
|
<para>The UEFI boot stub looks for various resources for the kernel invocation inside the UEFI PE binary
|
|
itself. This allows combining various resources inside a single PE binary image, which may then be signed
|
|
via UEFI SecureBoot as a whole, covering all individual resources at once. Specifically it may
|
|
include:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><para>The ELF Linux kernel images will be looked for in the <literal>.linux</literal> PE
|
|
section of the executed image.</para></listitem>
|
|
|
|
<listitem><para>OS release information, i.e. the
|
|
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> file of
|
|
the OS the kernel belongs to, in the <literal>.osrel</literal> PE section.</para></listitem>
|
|
|
|
<listitem><para>The initial RAM disk (initrd) will be looked for in the <literal>.initrd</literal> PE
|
|
section.</para></listitem>
|
|
|
|
<listitem><para>A compiled binary DeviceTree will be looked for in the <literal>.dtb</literal> PE
|
|
section.</para></listitem>
|
|
|
|
<listitem><para>The kernel command line to pass to the invoked kernel will be looked for in the
|
|
<literal>.cmdline</literal> PE section.</para></listitem>
|
|
|
|
<listitem><para>A boot splash (in Windows <filename>.BMP</filename> format) to show on screen before
|
|
invoking the kernel will be looked for in the <literal>.splash</literal> PE section.</para></listitem>
|
|
</itemizedlist>
|
|
|
|
<para>If UEFI SecureBoot is enabled and the <literal>.cmdline</literal> section is present in the executed
|
|
image, any attempts to override the kernel command line by passing one as invocation parameters to the
|
|
EFI binary are ignored. Thus, in order to allow overriding the kernel command line, either disable UEFI
|
|
SecureBoot, or don't include a kernel command line PE section in the kernel image file. If a command line
|
|
is accepted via EFI invocation parameters to the EFI binary it is measured into TPM PCR 12 (if a TPM is
|
|
present).</para>
|
|
|
|
<para>If a DeviceTree is embedded in the <literal>.dtb</literal> section, it replaces an existing
|
|
DeviceTree in the corresponding EFI configuration table. systemd-stub will ask the firmware via the
|
|
<literal>EFI_DT_FIXUP_PROTOCOL</literal> for hardware specific fixups to the DeviceTree.</para>
|
|
|
|
<para>The contents of these six PE sections are measured into TPM PCR 11, that is otherwise not
|
|
used. Thus, it can be pre-calculated without too much effort.</para>
|
|
</refsect1>
|
|
|
|
<refsect1>
|
|
<title>Companion Files</title>
|
|
|
|
<para>The <command>systemd-stub</command> UEFI boot stub automatically collects two types of auxiliary
|
|
companion files optionally placed in drop-in directories on the same partition as the EFI binary,
|
|
dynamically generates <command>cpio</command> initrd archives from them, and passes them to the kernel.
|
|
Specifically:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><para>For a kernel binary called <filename><replaceable>foo</replaceable>.efi</filename>, it
|
|
will look for files with the <filename>.cred</filename> suffix in a directory named
|
|
<filename><replaceable>foo</replaceable>.efi.extra.d/</filename> next to it. A <command>cpio</command>
|
|
archive is generated from all files found that way, placing them in the
|
|
<filename>/.extra/credentials/</filename> directory of the initrd file hierarchy. The main initrd may
|
|
then access them in this directory. This is supposed to be used to store auxiliary, encrypted,
|
|
authenticated credentials for use with <varname>LoadCredentialEncrypted=</varname> in the UEFI System
|
|
Partition. See
|
|
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
|
and
|
|
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
|
for
|
|
details on encrypted credentials. The generated <command>cpio</command> archive is measured into TPM
|
|
PCR 12 (if a TPM is present).</para></listitem>
|
|
|
|
<listitem><para>Similarly, files <filename><replaceable>foo</replaceable>.efi.extra.d/*.raw</filename>
|
|
are packed up in a <command>cpio</command> archive and placed in the <filename>/.extra/sysext/</filename>
|
|
directory in the initrd file hierarchy. This is supposed to be used to pass additional system extension
|
|
images to the initrd. See
|
|
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
|
|
details on system extension images. The generated <command>cpio</command> archive containing these
|
|
system extension images is measured into TPM PCR 13 (if a TPM is present).</para></listitem>
|
|
|
|
<listitem><para>Files <filename>/loader/credentials/*.cred</filename> are packed up in a
|
|
<command>cpio</command> archive and placed in the <filename>/.extra/global_credentials/</filename>
|
|
directory of the initrd file hierarchy. This is supposed to be used to pass additional credentials to
|
|
the initrd, regardless of the kernel being booted. The generated <command>cpio</command> archive is
|
|
measured into TPM PCR 12 (if a TPM is present)</para></listitem>
|
|
</itemizedlist>
|
|
|
|
<para>These mechanisms may be used to parameterize and extend trusted (i.e. signed), immutable initrd
|
|
images in a reasonably safe way: all data they contain is measured into TPM PCRs. On access they should be
|
|
further validated: in case of the credentials case by encrypting/authenticating them via TPM, as exposed
|
|
by <command>systemd-creds encrypt -T</command> (see
|
|
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
|
details); in case of the system extension images by using signed Verity images.</para>
|
|
</refsect1>
|
|
|
|
<refsect1>
|
|
<title>TPM2 PCR Notes</title>
|
|
|
|
<para>Note that when a unified kernel using <command>systemd-stub</command> is invoked the firmware will
|
|
measure it as a whole to TPM PCR 4, covering all embedded resources, such as the stub code itself, the
|
|
core kernel, the embedded initrd and kernel command line (see above for a full list).</para>
|
|
|
|
<para>Also note that the Linux kernel will measure all initrds it receives into TPM PCR 9. This means
|
|
every type of initrd will be measured two or three times: the initrd embedded in the kernel image will be
|
|
measured to PCR 4, PCR 9 and PCR 11; the initrd synthesized from credentials will be measured to both PCR
|
|
9 and PCR 12; the initrd synthesized from system extensions will be measured to both PCR 4 and PCR
|
|
9. Let's summarize the OS resources and the PCRs they are measured to:</para>
|
|
|
|
<table>
|
|
<title>OS Resource PCR Summary</title>
|
|
|
|
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
|
|
<colspec colname="pcr" />
|
|
<colspec colname="definition" />
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>OS Resource</entry>
|
|
<entry>Measurement PCR</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><command>systemd-stub</command> code (the entry point of the unified PE binary)</entry>
|
|
<entry>4</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>Boot splash (embedded in the unified PE binary)</entry>
|
|
<entry>4 + 11</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>Core kernel code (embedded in unified PE binary)</entry>
|
|
<entry>4 + 11</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>Main initrd (embedded in unified PE binary)</entry>
|
|
<entry>4 + 9 + 11</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>Default kernel command line (embedded in unified PE binary)</entry>
|
|
<entry>4 + 11</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>Overridden kernel command line</entry>
|
|
<entry>12</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>Credentials (synthesized initrd from companion files)</entry>
|
|
<entry>9 + 12</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>System Extensions (synthesized initrd from companion files)</entry>
|
|
<entry>9 + 13</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</refsect1>
|
|
|
|
<refsect1>
|
|
<title>EFI Variables</title>
|
|
|
|
<para>The following EFI variables are defined, set and read by <command>systemd-stub</command>, under the
|
|
vendor UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</literal>, for communication between the boot
|
|
stub and the OS:</para>
|
|
|
|
<variablelist class='efi-variables'>
|
|
<varlistentry>
|
|
<term><varname>LoaderDevicePartUUID</varname></term>
|
|
|
|
<listitem><para>Contains the partition UUID of the EFI System Partition the EFI image was run
|
|
from. <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
|
uses this information to automatically find the disk booted from, in order to discover various other
|
|
partitions on the same disk automatically.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>LoaderFirmwareInfo</varname></term>
|
|
<term><varname>LoaderFirmwareType</varname></term>
|
|
|
|
<listitem><para>Brief firmware information. Use
|
|
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to view this
|
|
data.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>LoaderImageIdentifier</varname></term>
|
|
|
|
<listitem><para>The path of EFI executable, relative to the EFI System Partition's root
|
|
directory. Use
|
|
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to view
|
|
this data.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>StubInfo</varname></term>
|
|
|
|
<listitem><para>Brief stub information. Use
|
|
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to view
|
|
this data.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>StubPcrKernelImage</varname></term>
|
|
|
|
<listitem><para>The PCR register index the ELF kernel image/initial RAM disk image/boot
|
|
splash/devicetree database/embedded command line are measured into, formatted as decimal ASCII string
|
|
(i.e. <literal>11</literal>). This variable is set if a measurement was successfully completed, and
|
|
remains unset otherwise.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>StubPcrKernelParameters</varname></term>
|
|
|
|
<listitem><para>The PCR register index the kernel command line and credentials are measured into,
|
|
formatted as decimal ASCII string (i.e. <literal>12</literal>). This variable is set if a measurement
|
|
was successfully completed, and remains unset otherwise.</para></listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><varname>StubPcrInitRDSysExts</varname></term>
|
|
|
|
<listitem><para>The PCR register index the systemd extensions for the initial RAM disk image, which
|
|
are picked up from the file system the kernel image is located on. Formatted as decimal ASCII string
|
|
(i.e. <literal>13</literal>). This variable is set if a measurement was successfully completed, and
|
|
remains unset otherwise.</para></listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para>Note that some of the variables above may also be set by the boot loader. The stub will only set
|
|
them if they aren't set already. Some of these variables are defined by the <ulink
|
|
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>.</para>
|
|
</refsect1>
|
|
|
|
<refsect1>
|
|
<title>Assembling Kernel Images</title>
|
|
|
|
<para>In order to assemble an UEFI PE kernel image from various components as described above, use an
|
|
<citerefentry project='man-pages'><refentrytitle>objcopy</refentrytitle><manvolnum>1</manvolnum></citerefentry> command line
|
|
like this:</para>
|
|
|
|
<programlisting>objcopy \
|
|
--add-section .osrel=os-release --change-section-vma .osrel=0x20000 \
|
|
--add-section .cmdline=cmdline.txt --change-section-vma .cmdline=0x30000 \
|
|
--add-section .dtb=devicetree.dtb --change-section-vma .dtb=0x40000 \
|
|
--add-section .splash=splash.bmp --change-section-vma .splash=0x100000 \
|
|
--add-section .linux=vmlinux --change-section-vma .linux=0x2000000 \
|
|
--add-section .initrd=initrd.cpio --change-section-vma .initrd=0x3000000 \
|
|
/usr/lib/systemd/boot/efi/linuxx64.efi.stub \
|
|
foo-unsigned.efi</programlisting>
|
|
|
|
<para>This generates one PE executable file <filename>foo-unsigned.efi</filename> from the six individual
|
|
files for OS release information, kernel command line, boot splash image, kernel image, main initrd and
|
|
UEFI boot stub.</para>
|
|
|
|
<para>To then sign the resulting image for UEFI SecureBoot use an
|
|
<citerefentry project='archlinux'><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry> command like
|
|
the following:</para>
|
|
|
|
<programlisting>sbsign \
|
|
--key mykey.pem \
|
|
--cert mykey.crt \
|
|
--output foo.efi \
|
|
foo-unsigned.efi</programlisting>
|
|
|
|
<para>This expects a pair of X.509 private key and certificate as parameters and then signs the UEFI PE
|
|
executable we generated above for UEFI SecureBoot and generates a signed UEFI PE executable as
|
|
result.</para>
|
|
</refsect1>
|
|
|
|
<refsect1>
|
|
<title>See Also</title>
|
|
<para>
|
|
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
|
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
|
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
|
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
|
<ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>,
|
|
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>,
|
|
<citerefentry project='man-pages'><refentrytitle>objcopy</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
|
<citerefentry project='archlinux'><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
|
</para>
|
|
</refsect1>
|
|
</refentry>
|