summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/TPM2_PCR_MEASUREMENTS.md10
-rw-r--r--man/systemd-stub.xml15
-rw-r--r--src/boot/efi/stub.c80
-rw-r--r--src/fundamental/tpm2-pcr.h3
4 files changed, 95 insertions, 13 deletions
diff --git a/docs/TPM2_PCR_MEASUREMENTS.md b/docs/TPM2_PCR_MEASUREMENTS.md
index 81c8aaa156..daee33980b 100644
--- a/docs/TPM2_PCR_MEASUREMENTS.md
+++ b/docs/TPM2_PCR_MEASUREMENTS.md
@@ -120,6 +120,16 @@ Devicetree addons are measured individually as a tagged event.
→ **Measured hash** covers the content of the Devicetree.
+### PCR 12, `EV_EVENT_TAG`, "Initrd addons"
+
+Initrd addons are measured individually as a tagged event.
+
+→ **Event Tag** `0x49dffe0f`
+
+→ **Description** the addon filename.
+
+→ **Measured hash** covers the contents of the initrd.
+
### PCR 12, `EV_EVENT_TAG`, "Ucode addons"
Ucode addons are measured individually as a tagged event.
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index 18f3023a65..439d999c64 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -193,9 +193,10 @@
<filename><replaceable>foo</replaceable>.efi.extra.d/*.addon.efi</filename> are loaded and verified as
PE binaries and specific sections are loaded from them. Addons are used to pass additional kernel
command line parameters (<literal>.cmdline</literal> section), or Devicetree blobs
- (<literal>.dtb</literal> section), and microcode updates (<literal>.ucode</literal> section). Addons
- allow those resources to be passed regardless of the kernel version being booted, for example allowing
- platform vendors to ship platform-specific configuration.</para>
+ (<literal>.dtb</literal> section), additional initrds (<literal>.initrd</literal> section),
+ and microcode updates (<literal>.ucode</literal> section). Addons allow those resources to be passed
+ regardless of the kernel version being booted, for example allowing platform vendors to ship
+ platform-specific configuration.</para>
<para>In case Secure Boot is enabled, these files will be validated using keys in UEFI DB, Shim's DB or
Shim's MOK, and only loaded if the check passes. Additionally, if both the addon and the UKI contain a
@@ -227,10 +228,10 @@
archive is measured into TPM PCR 12 (if a TPM is present).</para></listitem>
<listitem><para>Additionally, files <filename>/loader/addons/*.addon.efi</filename> are loaded and
- verified as PE binaries, and <literal>.cmdline</literal>, <literal>.dtb</literal>, and
- <literal>.ucode</literal> sections are parsed from them. This is supposed to be used to pass additional
- command line parameters, DeviceTree blobs, and microcode updates to the kernel, regardless of the
- kernel version being booted.</para></listitem>
+ verified as PE binaries, and <literal>.cmdline</literal>, <literal>.dtb</literal>,
+ <literal>.initrd</literal>, and <literal>.ucode</literal> sections are parsed from them.
+ This is supposed to be used to pass additional command line parameters, DeviceTree blobs, initrds,
+ and microcode updates to the kernel, regardless of the kernel version being booted.</para></listitem>
</itemizedlist>
<para>These mechanisms may be used to parameterize and extend trusted (i.e. signed), immutable initrd
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 3872504232..4fc2174669 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -449,6 +449,42 @@ static inline void iovec_array_extend(struct iovec **arr, size_t *n_arr, struct
(*arr)[(*n_arr)++] = elem;
}
+static void measure_and_append_initrd_addons(
+ struct iovec **all_initrds,
+ size_t *n_all_initrds,
+ const NamedAddon *initrd_addons,
+ size_t n_initrd_addons,
+ int *sections_measured) {
+
+ EFI_STATUS err;
+
+ assert(all_initrds);
+ assert(n_all_initrds);
+ assert(initrd_addons || n_initrd_addons == 0);
+ assert(sections_measured);
+
+ FOREACH_ARRAY(i, initrd_addons, n_initrd_addons) {
+ bool m = false;
+ err = tpm_log_tagged_event(
+ TPM2_PCR_KERNEL_CONFIG,
+ POINTER_TO_PHYSICAL_ADDRESS(i->blob.iov_base),
+ i->blob.iov_len,
+ INITRD_ADDON_EVENT_TAG_ID,
+ i->filename,
+ &m);
+ if (err != EFI_SUCCESS)
+ return (void) log_error_status(
+ err,
+ "Unable to extend PCR %i with INITRD addon '%ls': %m",
+ TPM2_PCR_KERNEL_CONFIG,
+ i->filename);
+
+ combine_measured_flag(sections_measured, m);
+
+ iovec_array_extend(all_initrds, n_all_initrds, i->blob);
+ }
+}
+
static void measure_and_append_ucode_addons(
struct iovec **all_initrds,
size_t *n_all_initrds,
@@ -508,6 +544,8 @@ static EFI_STATUS load_addons(
char16_t **cmdline, /* Both input+output, extended with new addons we find */
NamedAddon **devicetree_addons, /* Ditto */
size_t *n_devicetree_addons,
+ NamedAddon **initrd_addons, /* Ditto */
+ size_t *n_initrd_addons,
NamedAddon **ucode_addons, /* Ditto */
size_t *n_ucode_addons) {
@@ -575,11 +613,12 @@ static EFI_STATUS load_addons(
if (err != EFI_SUCCESS ||
(!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_CMDLINE) &&
!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB) &&
+ !PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_INITRD) &&
!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_UCODE))) {
if (err == EFI_SUCCESS)
err = EFI_NOT_FOUND;
log_error_status(err,
- "Unable to locate embedded .cmdline/.dtb/.ucode sections in %ls, ignoring: %m",
+ "Unable to locate embedded .cmdline/.dtb/.initrd/.ucode sections in %ls, ignoring: %m",
items[i]);
continue;
}
@@ -621,6 +660,19 @@ static EFI_STATUS load_addons(
};
}
+ if (initrd_addons && PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_INITRD)) {
+ *initrd_addons = xrealloc(*initrd_addons,
+ *n_initrd_addons * sizeof(NamedAddon),
+ (*n_initrd_addons + 1) * sizeof(NamedAddon));
+ (*initrd_addons)[(*n_initrd_addons)++] = (NamedAddon) {
+ .blob = {
+ .iov_base = xmemdup((const uint8_t*) loaded_addon->ImageBase + sections[UNIFIED_SECTION_INITRD].memory_offset, sections[UNIFIED_SECTION_INITRD].size),
+ .iov_len = sections[UNIFIED_SECTION_INITRD].size,
+ },
+ .filename = xstrdup16(items[i]),
+ };
+ }
+
if (ucode_addons && PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_UCODE)) {
*ucode_addons = xrealloc(*ucode_addons,
*n_ucode_addons * sizeof(NamedAddon),
@@ -933,6 +985,8 @@ static void load_all_addons(
char16_t **cmdline_addons,
NamedAddon **dt_addons,
size_t *n_dt_addons,
+ NamedAddon **initrd_addons,
+ size_t *n_initrd_addons,
NamedAddon **ucode_addons,
size_t *n_ucode_addons) {
@@ -942,6 +996,8 @@ static void load_all_addons(
assert(cmdline_addons);
assert(dt_addons);
assert(n_dt_addons);
+ assert(initrd_addons);
+ assert(n_initrd_addons);
assert(ucode_addons);
assert(n_ucode_addons);
@@ -953,6 +1009,8 @@ static void load_all_addons(
cmdline_addons,
dt_addons,
n_dt_addons,
+ initrd_addons,
+ n_initrd_addons,
ucode_addons,
n_ucode_addons);
if (err != EFI_SUCCESS)
@@ -971,6 +1029,8 @@ static void load_all_addons(
cmdline_addons,
dt_addons,
n_dt_addons,
+ initrd_addons,
+ n_initrd_addons,
ucode_addons,
n_ucode_addons);
if (err != EFI_SUCCESS)
@@ -1097,8 +1157,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
PeSectionVector sections[ELEMENTSOF(unified_sections)] = {};
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
_cleanup_free_ char *uname = NULL;
- NamedAddon *dt_addons = NULL, *ucode_addons = NULL;
- size_t n_dt_addons = 0, n_ucode_addons = 0;
+ NamedAddon *dt_addons = NULL, *initrd_addons = NULL, *ucode_addons = NULL;
+ size_t n_dt_addons = 0, n_initrd_addons = 0, n_ucode_addons = 0;
_cleanup_free_ struct iovec *all_initrds = NULL;
size_t n_all_initrds = 0;
unsigned profile = 0;
@@ -1134,8 +1194,9 @@ static EFI_STATUS run(EFI_HANDLE image) {
/* Now that we have the UKI sections loaded, also load global first and then local (per-UKI)
* addons. The data is loaded at once, and then used later. */
CLEANUP_ARRAY(dt_addons, n_dt_addons, named_addon_free_many);
+ CLEANUP_ARRAY(initrd_addons, n_initrd_addons, named_addon_free_many);
CLEANUP_ARRAY(ucode_addons, n_ucode_addons, named_addon_free_many);
- load_all_addons(image, loaded_image, uname, &cmdline_addons, &dt_addons, &n_dt_addons, &ucode_addons, &n_ucode_addons);
+ load_all_addons(image, loaded_image, uname, &cmdline_addons, &dt_addons, &n_dt_addons, &initrd_addons, &n_initrd_addons, &ucode_addons, &n_ucode_addons);
/* If we have any extra command line to add via PE addons, load them now and append, and measure the
* additions together, after the embedded options, but before the smbios ones, so that the order is
@@ -1156,10 +1217,17 @@ static EFI_STATUS run(EFI_HANDLE image) {
generate_embedded_initrds(loaded_image, sections, initrds);
lookup_embedded_initrds(loaded_image, sections, initrds);
- /* Measures ucode addons and puts them into all_initrds */
+ /* Add initrds in the right order. Generally, later initrds can overwrite files in earlier ones,
+ * except for ucode, where the kernel uses the first matching embedded filename.
+ * We want addons to take precedence over the base initrds, so the order is:
+ * 1. Ucode addons
+ * 2. UKI ucode
+ * 3. UKI initrd
+ * 4. Generated initrds
+ * 5. initrd addons */
measure_and_append_ucode_addons(&all_initrds, &n_all_initrds, ucode_addons, n_ucode_addons, &parameters_measured);
- /* Adds all other initrds to all_initrds */
extend_initrds(initrds, &all_initrds, &n_all_initrds);
+ measure_and_append_initrd_addons(&all_initrds, &n_all_initrds, initrd_addons, n_initrd_addons, &parameters_measured);
/* Export variables indicating what we measured */
export_pcr_variables(sections_measured, parameters_measured, sysext_measured, confext_measured);
diff --git a/src/fundamental/tpm2-pcr.h b/src/fundamental/tpm2-pcr.h
index 9f5529b827..f903ec3e3b 100644
--- a/src/fundamental/tpm2-pcr.h
+++ b/src/fundamental/tpm2-pcr.h
@@ -50,6 +50,9 @@ enum {
/* The tag used for EV_EVENT_TAG event log records covering Devicetree blobs */
#define DEVICETREE_ADDON_EVENT_TAG_ID UINT32_C(0x6c46f751)
+/* The tag used for EV_EVENT_TAG event log records covering initrd addons */
+#define INITRD_ADDON_EVENT_TAG_ID UINT32_C(0x49dffe0f)
+
/* The tag used for EV_EVENT_TAG event log records covering ucode addons (effectively initrds) */
#define UCODE_ADDON_EVENT_TAG_ID UINT32_C(0xdac08e1a)