<entry>The IMA project measures its runtime state into this PCR.</entry>
</row>
+ <row>
+ <entry>11</entry>
+ <entry><citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures the ELF kernel image, embedded initrd and other payload of the PE image it is placed in into this PCR. Unlike PCR 4 (where the same data should be measured into), this PCR value should be easy to pre-calculate, as this only contains static parts of the PE binary. Use this PCR to bind TPM policies to a specific kernel image, possibly with an embedded initial RAM disk (initrd).</entry>
+ </row>
+
<row>
<entry>12</entry>
<entry><citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures any specified kernel command line into this PCR. <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures any manually specified kernel command line (i.e. a kernel command line that overrides the one embedded in the unified PE image) and loaded credentials into this PCR. (Note that if <command>systemd-boot</command> and <command>systemd-stub</command> are used in combination the command line might be measured twice!)</entry>
<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>
<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>
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 twice: the initrd embedded in the kernel image will be measured to
- both PCR 4 and PCR 9; the initrd synthesized from credentials will be measured to both PCR 12 and PCR 9;
- 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>
+ 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>
<row>
<entry>Boot splash (embedded in the unified PE binary)</entry>
- <entry>4</entry>
+ <entry>4 + 11</entry>
</row>
<row>
<entry>Core kernel code (embedded in unified PE binary)</entry>
- <entry>4</entry>
+ <entry>4 + 11</entry>
</row>
<row>
<entry>Main initrd (embedded in unified PE binary)</entry>
- <entry>4 + 9</entry>
+ <entry>4 + 9 + 11</entry>
</row>
<row>
<entry>Default kernel command line (embedded in unified PE binary)</entry>
- <entry>4</entry>
+ <entry>4 + 11</entry>
</row>
<row>
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>
#include <stdbool.h>
#include <uchar.h>
+/* This TPM PCR is where we extend the sd-stub "payloads" into, before using them. i.e. the kernel ELF image,
+ * embedded initrd, and so on. In contrast to PCR 4 (which also contains this data, given the whole
+ * surrounding PE image is measured into it) this should be reasonably pre-calculatable, because it *only*
+ * consists of static data from the kernel PE image. */
+#define TPM_PCR_INDEX_KERNEL_IMAGE 11U
+
/* This TPM PCR is where sd-stub extends the kernel command line and any passed credentials into. */
#define TPM_PCR_INDEX_KERNEL_PARAMETERS 12U
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
- enum {
+ enum Section {
SECTION_CMDLINE,
SECTION_LINUX,
SECTION_INITRD,
UINTN szs[_SECTION_MAX] = {};
char *cmdline = NULL;
_cleanup_free_ char *cmdline_owned = NULL;
- int parameters_measured = -1;
+ int sections_measured = -1, parameters_measured = -1;
EFI_STATUS err;
bool m;
return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
}
+ /* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written
+ * into so far), so that we have one PCR that we can nicely write policies against because it
+ * contains all static data of this image, and thus can be easily be pre-calculated. */
+ for (enum Section section = 0; section < _SECTION_MAX; section++) {
+ m = false;
+
+ if (szs[section] == 0) /* not found */
+ continue;
+
+ /* First measure the name of the section */
+ (void) tpm_log_event_ascii(
+ TPM_PCR_INDEX_KERNEL_IMAGE,
+ POINTER_TO_PHYSICAL_ADDRESS(sections[section]),
+ strsize8(sections[section]), /* including NUL byte */
+ sections[section],
+ &m);
+
+ sections_measured = sections_measured < 0 ? m : (sections_measured && m);
+
+ /* Then measure the data of the section */
+ (void) tpm_log_event_ascii(
+ TPM_PCR_INDEX_KERNEL_IMAGE,
+ POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[section],
+ szs[section],
+ sections[section],
+ &m);
+
+ sections_measured = sections_measured < 0 ? m : (sections_measured && m);
+ }
+
+ /* After we are done, set an EFI variable that tells userspace this was done successfully, and encode
+ * in it which PCR was used. */
+ if (sections_measured > 0)
+ (void) efivar_set_uint_string(LOADER_GUID, L"StubPcrKernelImage", TPM_PCR_INDEX_KERNEL_IMAGE, 0);
+
/* Show splash screen as early as possible */
graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[SECTION_SPLASH], szs[SECTION_SPLASH], NULL);