sd-stub: make initrd passing incremental + other EFI prep work for #41543 (#41748)

This is split out of #41543 but I think makes sense of its own.

It primary does one thing: ensure that initrds installed via the Linux EFI protocol are incremental in behaviour (i.e. we read the previously set initrd and combine it with ours). So far we'd simply not install any initrds at all in this case, which would break stuff.

THis is preparatory for #41543, but is generally the better, safer behaviour.

This also contains three minor changes which are purley prep work for #41543 but shouldn't hurt in the big picture.
This commit is contained in:
Daan De Meyer
2026-04-22 14:24:03 +02:00
committed by GitHub
5 changed files with 297 additions and 133 deletions
+77 -33
View File
@@ -52,12 +52,11 @@ static char *pad4(char *p, const char *start) {
return p;
}
static EFI_STATUS pack_cpio_one(
EFI_STATUS pack_cpio_one(
const char16_t *fname,
const void *contents,
size_t contents_size,
const char *target_dir_prefix,
uint32_t access_mode,
const CpioTarget *target,
uint32_t *inode_counter,
void **cpio_buffer,
size_t *cpio_buffer_size) {
@@ -67,7 +66,7 @@ static EFI_STATUS pack_cpio_one(
assert(fname);
assert(contents || contents_size == 0);
assert(target_dir_prefix);
assert(target);
assert(inode_counter);
assert(cpio_buffer);
assert(cpio_buffer_size);
@@ -84,7 +83,7 @@ static EFI_STATUS pack_cpio_one(
l = 6 + 13*8 + 1 + 1; /* Fixed CPIO header size, slash separator, and NUL byte after the file name */
target_dir_prefix_size = strlen8(target_dir_prefix);
target_dir_prefix_size = strlen8(target->directory);
if (l > SIZE_MAX - target_dir_prefix_size)
return EFI_OUT_OF_RESOURCES;
l += target_dir_prefix_size;
@@ -121,11 +120,11 @@ static EFI_STATUS pack_cpio_one(
a = mempcpy(a, "070701", 6); /* magic ID */
a = write_cpio_word(a, (*inode_counter)++); /* inode */
a = write_cpio_word(a, access_mode | 0100000 /* = S_IFREG */); /* mode */
a = write_cpio_word(a, 0); /* uid */
a = write_cpio_word(a, 0); /* gid */
a = write_cpio_word(a, 1); /* nlink */
a = write_cpio_word(a, (*inode_counter)++); /* inode */
a = write_cpio_word(a, target->access_mode | 0100000 /* = S_IFREG */); /* mode */
a = write_cpio_word(a, 0); /* uid */
a = write_cpio_word(a, 0); /* gid */
a = write_cpio_word(a, 1); /* nlink */
/* Note: we don't make any attempt to propagate the mtime here, for two reasons: it's a mess given
* that FAT usually is assumed to operate with timezoned timestamps, while UNIX does not. More
@@ -141,7 +140,7 @@ static EFI_STATUS pack_cpio_one(
a = write_cpio_word(a, target_dir_prefix_size + fname_size + 2); /* fname size */
a = write_cpio_word(a, 0); /* "crc" */
a = mempcpy(a, target_dir_prefix, target_dir_prefix_size);
a = mempcpy(a, target->directory, target_dir_prefix_size);
*(a++) = '/';
a = mangle_filename(a, fname);
@@ -225,16 +224,15 @@ static EFI_STATUS pack_cpio_dir(
return EFI_SUCCESS;
}
static EFI_STATUS pack_cpio_prefix(
const char *path,
uint32_t dir_mode,
EFI_STATUS pack_cpio_prefix(
const CpioTarget *target,
uint32_t *inode_counter,
void **cpio_buffer,
size_t *cpio_buffer_size) {
EFI_STATUS err;
assert(path);
assert(target);
assert(inode_counter);
assert(cpio_buffer);
assert(cpio_buffer_size);
@@ -243,7 +241,7 @@ static EFI_STATUS pack_cpio_prefix(
* (similar to mkdir -p behaviour) all leading paths are created with 0555 access mode, only the
* final dir is created with the specified directory access mode. */
for (const char *p = path;;) {
for (const char *p = target->directory;;) {
const char *e;
e = strchr8(p, '/');
@@ -253,7 +251,7 @@ static EFI_STATUS pack_cpio_prefix(
if (e > p) {
_cleanup_free_ char *t = NULL;
t = xstrndup8(path, e - path);
t = xstrndup8(target->directory, e - target->directory);
if (!t)
return EFI_OUT_OF_RESOURCES;
@@ -265,10 +263,10 @@ static EFI_STATUS pack_cpio_prefix(
p = e + 1;
}
return pack_cpio_dir(path, dir_mode, inode_counter, cpio_buffer, cpio_buffer_size);
return pack_cpio_dir(target->directory, target->dir_mode, inode_counter, cpio_buffer, cpio_buffer_size);
}
static EFI_STATUS pack_cpio_trailer(
EFI_STATUS pack_cpio_trailer(
void **cpio_buffer,
size_t *cpio_buffer_size) {
@@ -307,9 +305,7 @@ EFI_STATUS pack_cpio(
const char16_t *dropin_dir,
const char16_t *match_suffix,
const char16_t *exclude_suffix,
const char *target_dir_prefix,
uint32_t dir_mode,
uint32_t access_mode,
const CpioTarget *target,
uint32_t tpm_pcr,
const char16_t *tpm_description,
struct iovec *ret_buffer,
@@ -325,7 +321,7 @@ EFI_STATUS pack_cpio(
EFI_STATUS err;
assert(loaded_image);
assert(target_dir_prefix);
assert(target);
assert(ret_buffer);
if (!loaded_image->DeviceHandle)
@@ -400,7 +396,7 @@ EFI_STATUS pack_cpio(
/* Generate the leading directory inodes right before adding the first files, to the
* archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
err = pack_cpio_prefix(target, &inode, &buffer, &buffer_size);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to pack cpio prefix: %m");
@@ -417,8 +413,7 @@ EFI_STATUS pack_cpio(
err = pack_cpio_one(
items[i],
content, contentsize,
target_dir_prefix,
access_mode,
target,
&inode,
&buffer, &buffer_size);
if (err != EFI_SUCCESS)
@@ -453,10 +448,8 @@ nothing:
EFI_STATUS pack_cpio_literal(
const void *data,
size_t data_size,
const char *target_dir_prefix,
const CpioTarget *target,
const char16_t *target_filename,
uint32_t dir_mode,
uint32_t access_mode,
uint32_t tpm_pcr,
const char16_t *tpm_description,
struct iovec *ret_buffer,
@@ -468,22 +461,21 @@ EFI_STATUS pack_cpio_literal(
EFI_STATUS err;
assert(data || data_size == 0);
assert(target_dir_prefix);
assert(target);
assert(target_filename);
assert(ret_buffer);
/* Generate the leading directory inodes right before adding the first files, to the
* archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
err = pack_cpio_prefix(target, &inode, &buffer, &buffer_size);
if (err != EFI_SUCCESS)
return log_error_status(err, "Failed to pack cpio prefix: %m");
err = pack_cpio_one(
target_filename,
data, data_size,
target_dir_prefix,
access_mode,
target,
&inode,
&buffer, &buffer_size);
if (err != EFI_SUCCESS)
@@ -505,3 +497,55 @@ EFI_STATUS pack_cpio_literal(
*ret_buffer = IOVEC_MAKE(TAKE_PTR(buffer), buffer_size);
return EFI_SUCCESS;
}
/* The following are canonical definitions of the various cpio target directories we place resources in. We
* define them here in a single canonical list of targets because we need to reuse them at various places
* (well, some of them at least), and we don't want the access modes to deviate slightly on each use. */
const CpioTarget cpio_target_credentials = {
.directory = ".extra/credentials",
.dir_mode = 0500,
.access_mode = 0400,
};
const CpioTarget cpio_target_global_credentials = {
.directory = ".extra/global_credentials",
.dir_mode = 0500,
.access_mode = 0400,
};
const CpioTarget cpio_target_sysext = {
.directory = ".extra/sysext",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_global_sysext = {
.directory = ".extra/global_sysext",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_confext = {
.directory = ".extra/confext",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_global_confext = {
.directory = ".extra/global_confext",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_meta = {
.directory = ".extra",
.dir_mode = 0555,
.access_mode = 0444,
};
const CpioTarget cpio_target_meta_secret = {
.directory = ".extra",
.dir_mode = 0555,
.access_mode = 0400,
};
+36 -6
View File
@@ -4,14 +4,37 @@
#include "efi.h"
#include "proto/loaded-image.h"
typedef struct CpioTarget {
const char *directory; /* Path to directory where to place resources */
uint32_t dir_mode; /* Access mode for the directory */
uint32_t access_mode; /* Access mode for the files in the directory */
} CpioTarget;
EFI_STATUS pack_cpio_one(
const char16_t *fname,
const void *contents,
size_t contents_size,
const CpioTarget *target,
uint32_t *inode_counter,
void **cpio_buffer,
size_t *cpio_buffer_size);
EFI_STATUS pack_cpio_prefix(
const CpioTarget *target,
uint32_t *inode_counter,
void **cpio_buffer,
size_t *cpio_buffer_size);
EFI_STATUS pack_cpio_trailer(
void **cpio_buffer,
size_t *cpio_buffer_size);
EFI_STATUS pack_cpio(
EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
const char16_t *dropin_dir,
const char16_t *match_suffix,
const char16_t *exclude_suffix,
const char *target_dir_prefix,
uint32_t dir_mode,
uint32_t access_mode,
const CpioTarget *target,
uint32_t tpm_pcr,
const char16_t *tpm_description,
struct iovec *ret_buffer,
@@ -20,11 +43,18 @@ EFI_STATUS pack_cpio(
EFI_STATUS pack_cpio_literal(
const void *data,
size_t data_size,
const char *target_dir_prefix,
const CpioTarget *target,
const char16_t *target_filename,
uint32_t dir_mode,
uint32_t access_mode,
uint32_t tpm_pcr,
const char16_t *tpm_description,
struct iovec *ret_buffer,
bool *ret_measured);
extern const CpioTarget cpio_target_credentials;
extern const CpioTarget cpio_target_global_credentials;
extern const CpioTarget cpio_target_sysext;
extern const CpioTarget cpio_target_global_sysext;
extern const CpioTarget cpio_target_confext;
extern const CpioTarget cpio_target_global_confext;
extern const CpioTarget cpio_target_meta;
extern const CpioTarget cpio_target_meta_secret;
+139 -13
View File
@@ -71,8 +71,6 @@ EFI_STATUS initrd_register(
EFI_HANDLE *ret_initrd_handle) {
EFI_STATUS err;
EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) &efi_initrd_device_path;
EFI_HANDLE handle;
assert(ret_initrd_handle);
@@ -82,12 +80,43 @@ EFI_STATUS initrd_register(
if (!iovec_is_set(initrd))
return EFI_SUCCESS;
/* Check if a LINUX_INITRD_MEDIA_GUID DevicePath is already registered. LocateDevicePath checks for
* the "closest DevicePath" and returns its handle, whereas InstallMultipleProtocolInterfaces() only
* matches identical DevicePaths. */
err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), &dp, &handle);
if (err != EFI_NOT_FOUND) /* InitrdMedia is already registered */
return EFI_ALREADY_STARTED;
/* We want to override the LINUX_INITRD_MEDIA device, let's hence first unregister any existing
* one. We don't really expect multiple of these to be registered, but who knows? Let's kill all we
* can find. */
for (unsigned attempt = 0;; attempt++) {
if (attempt >= 16)
return log_debug_status(EFI_DEVICE_ERROR, "Unable to free LINUX_INITRD_MEDIA device path after %u attempts, giving up.", attempt);
EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) &efi_initrd_device_path;
EFI_HANDLE handle = NULL;
err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), &dp, &handle);
if (err == EFI_NOT_FOUND) /* Yay! All gone */
break;
if (err != EFI_SUCCESS)
return log_debug_status(err, "Failed to locate LINUX_INITRD_MEDIA device: %m");
/* Get the *actually* installed pointer for the device path */
err = BS->HandleProtocol(handle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void**) &dp);
if (err != EFI_SUCCESS)
return log_debug_status(err, "Failed to acquire DevicePath protocol on LINUX_INITRD_MEDIA device: %m");
/* Take away the device path protocol */
err = BS->UninstallMultipleProtocolInterfaces(
handle,
MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), dp,
/* sentinel= */ NULL);
if (err != EFI_SUCCESS)
return log_debug_status(err, "Unable to release DevicePath protocol from old handle: %m");
/* NB: we leave the handle around (and thus leave the LoadFile2 protocol installed), because
* the owner might be unhappy if we destroy it for them. It will no longer have the device
* path we want to take possession of on it though. The assumption here is that whoever
* registered the device path is OK with the device path being taken away, even if it might
* not be OK with the handle being invalidated as a whole. */
log_debug("Successfully unregistered previous LINUX_INITRD_MEDIA device.");
}
_cleanup_free_ struct initrd_loader *loader = xnew(struct initrd_loader, 1);
*loader = (struct initrd_loader) {
@@ -122,15 +151,112 @@ EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle) {
if (err != EFI_SUCCESS)
return log_debug_status(err, "Failed to acquire LoadFile2 protocol on our own initrd handle: %m");
/* uninstall all protocols thus destroying the handle */
/* We uninstall the DevicePath and the LoadFile2 protocol in separate steps. That's because we want
* to gracefully handle the former (because it's OK if something else takes over the device path),
* but be strict on the latter, because that's genuinely ours */
(void) BS->UninstallMultipleProtocolInterfaces(
initrd_handle,
MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), &efi_initrd_device_path,
/* sentinel= */ NULL);
/* This second call will also invalidate the handle, because it should be the last protocol on the handle */
err = BS->UninstallMultipleProtocolInterfaces(
initrd_handle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL),
&efi_initrd_device_path, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL),
loader,
NULL);
initrd_handle,
MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), loader,
/* sentinel= */ NULL);
if (err != EFI_SUCCESS)
return log_debug_status(err, "Failed to uninstall LoadFile2 protocol from our own initrd handle: %m");
free(loader);
return EFI_SUCCESS;
}
EFI_STATUS initrd_read_previous(struct iovec *ret_initrd) {
EFI_STATUS err;
/* If there's already an initrd registered, read it out, so that we can incorporate it in ours */
assert(ret_initrd);
/* Get from the device path to the handle */
EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) &efi_initrd_device_path;
EFI_HANDLE handle;
err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), &dp, &handle);
if (err != EFI_SUCCESS)
return err;
/* Get from the handle to the protocol */
EFI_LOAD_FILE2_PROTOCOL *protocol = NULL;
err = BS->HandleProtocol(handle, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), (void**) &protocol);
if (err != EFI_SUCCESS)
return err;
size_t size = 0;
err = protocol->LoadFile(protocol, dp, /* bootPolicy= */ false, &size, /* Buffer= */ NULL);
if (err == EFI_SUCCESS) /* Success? Kinda unexpected given we set Buffer to NULL, but it probably
* means, that the file is zero-sized, let's treat it as such. */
size = 0;
else if (err != EFI_BUFFER_TOO_SMALL)
return err;
if (size == 0)
return EFI_NOT_FOUND; /* Treat empty initrds like missing ones */
_cleanup_free_ void *data = xmalloc(size);
err = protocol->LoadFile(protocol, dp, /* bootPolicy= */ false, &size, data);
if (err != EFI_SUCCESS)
return err;
*ret_initrd = (struct iovec) {
.iov_base = TAKE_PTR(data),
.iov_len = size,
};
return EFI_SUCCESS;
}
EFI_STATUS combine_initrds(
const struct iovec initrds[], size_t n_initrds,
Pages *ret_initrd_pages, size_t *ret_initrd_size) {
size_t n = 0;
/* Combine initrds by concatenation in memory */
assert(initrds || n_initrds == 0);
assert(ret_initrd_pages);
assert(ret_initrd_size);
FOREACH_ARRAY(i, initrds, n_initrds) {
/* some initrds (the ones from UKI sections) need padding, pad all to be safe */
size_t initrd_size = ALIGN4(i->iov_len);
if (n > SIZE_MAX - initrd_size)
return EFI_OUT_OF_RESOURCES;
n += initrd_size;
}
_cleanup_pages_ Pages pages = xmalloc_initrd_pages(n);
uint8_t *p = PHYSICAL_ADDRESS_TO_POINTER(pages.addr);
FOREACH_ARRAY(i, initrds, n_initrds) {
size_t pad;
p = mempcpy(p, i->iov_base, i->iov_len);
pad = ALIGN4(i->iov_len) - i->iov_len;
if (pad == 0)
continue;
memzero(p, pad);
p += pad;
}
assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p);
*ret_initrd_pages = TAKE_STRUCT(pages);
*ret_initrd_size = n;
return EFI_SUCCESS;
}
+6
View File
@@ -2,6 +2,8 @@
#pragma once
#include "efi.h"
#include "iovec-util-fundamental.h"
#include "util.h"
EFI_STATUS initrd_register(
const struct iovec *initrd,
@@ -13,3 +15,7 @@ static inline void cleanup_initrd(EFI_HANDLE *initrd_handle) {
(void) initrd_unregister(*initrd_handle);
*initrd_handle = NULL;
}
EFI_STATUS initrd_read_previous(struct iovec *ret_initrd);
EFI_STATUS combine_initrds(const struct iovec initrds[], size_t n_initrds, Pages *ret_initrd_pages, size_t *ret_initrd_size);
+39 -81
View File
@@ -10,6 +10,7 @@
#include "efi-string.h"
#include "export-vars.h"
#include "graphics.h"
#include "initrd.h"
#include "iovec-util-fundamental.h"
#include "linux.h"
#include "measure.h"
@@ -32,13 +33,10 @@
/* The list of initrds we combine into one, in the order we want to merge them */
enum {
/* The first two are part of the PE binary */
INITRD_UCODE,
INITRD_BASE,
/* The rest are dynamically generated, and hence in dynamic memory */
_INITRD_DYNAMIC_FIRST,
INITRD_CREDENTIAL = _INITRD_DYNAMIC_FIRST,
INITRD_UCODE, /* Part of the PE binary */
INITRD_PREVIOUS, /* initrd already configured via the EFI protocol before we were invoked */
INITRD_BASE, /* Part of the PE binary */
INITRD_CREDENTIAL,
INITRD_GLOBAL_CREDENTIAL,
INITRD_SYSEXT,
INITRD_GLOBAL_SYSEXT,
@@ -52,6 +50,8 @@ enum {
_INITRD_MAX,
};
#define INITRD_IS_STATIC(idx) IN_SET(idx, INITRD_UCODE, INITRD_BASE)
/* magic string to find in the binary image */
DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION " ####");
@@ -102,50 +102,6 @@ static void combine_measured_flag(int *value, int measured) {
*value = *value < 0 ? measured : *value && measured;
}
/* Combine initrds by concatenation in memory */
static EFI_STATUS combine_initrds(
const struct iovec initrds[], size_t n_initrds,
Pages *ret_initrd_pages, size_t *ret_initrd_size) {
size_t n = 0;
assert(initrds || n_initrds == 0);
assert(ret_initrd_pages);
assert(ret_initrd_size);
FOREACH_ARRAY(i, initrds, n_initrds) {
/* some initrds (the ones from UKI sections) need padding, pad all to be safe */
size_t initrd_size = ALIGN4(i->iov_len);
if (n > SIZE_MAX - initrd_size)
return EFI_OUT_OF_RESOURCES;
n += initrd_size;
}
_cleanup_pages_ Pages pages = xmalloc_initrd_pages(n);
uint8_t *p = PHYSICAL_ADDRESS_TO_POINTER(pages.addr);
FOREACH_ARRAY(i, initrds, n_initrds) {
size_t pad;
p = mempcpy(p, i->iov_base, i->iov_len);
pad = ALIGN4(i->iov_len) - i->iov_len;
if (pad == 0)
continue;
memzero(p, pad);
p += pad;
}
assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p);
*ret_initrd_pages = TAKE_STRUCT(pages);
*ret_initrd_size = n;
return EFI_SUCCESS;
}
static void export_stub_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image, unsigned profile) {
static const uint64_t stub_features =
EFI_STUB_FEATURE_REPORT_BOOT_PARTITION | /* We set LoaderDevicePartUUID */
@@ -550,6 +506,21 @@ static void extend_initrds(
iovec_array_extend(all_initrds, n_all_initrds, *i);
}
static void acquire_previous_initrd(struct iovec initrds[static _INITRD_MAX]) {
EFI_STATUS err;
/* NB: the assumption here is that any previously installed initrd are measured by whatever
* registered them, and we just pass them on here. */
err = initrd_read_previous(initrds + INITRD_PREVIOUS);
if (err == EFI_NOT_FOUND)
log_debug_status(err, "No previous initrd registered.");
else if (err != EFI_SUCCESS)
log_warning_status(err, "Failed to read previously registered initrd, ignoring.");
else
log_debug("Successfully loaded previously registered initrd (%zu bytes).", initrds[INITRD_PREVIOUS].iov_len);
}
static EFI_STATUS load_addons(
EFI_HANDLE stub_image,
EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
@@ -821,10 +792,11 @@ static void cmdline_append_and_measure_smbios(char16_t **cmdline, int *parameter
static void initrds_free(struct iovec (*initrds)[_INITRD_MAX]) {
assert(initrds);
/* Free the dynamic initrds, but leave the non-dynamic ones around */
/* Free the non-static initrds, but leave the static (i.e. PE embedded) ones around */
for (size_t i = _INITRD_DYNAMIC_FIRST; i < _INITRD_MAX; i++)
iovec_done((*initrds) + i);
for (size_t i = 0; i < _INITRD_MAX; i++)
if (!INITRD_IS_STATIC(i))
iovec_done((*initrds) + i);
}
static void generate_sidecar_initrds(
@@ -846,9 +818,7 @@ static void generate_sidecar_initrds(
/* dropin_dir= */ NULL,
u".cred",
/* exclude_suffix= */ NULL,
".extra/credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
&cpio_target_credentials,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Credentials initrd",
initrds + INITRD_CREDENTIAL,
@@ -859,9 +829,7 @@ static void generate_sidecar_initrds(
u"\\loader\\credentials",
u".cred",
/* exclude_suffix= */ NULL,
".extra/global_credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
&cpio_target_global_credentials,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Global credentials initrd",
initrds + INITRD_GLOBAL_CREDENTIAL,
@@ -872,9 +840,7 @@ static void generate_sidecar_initrds(
/* dropin_dir= */ NULL,
u".raw", /* ideally we'd pick up only *.sysext.raw here, but for compat we pick up *.raw instead … */
u".confext.raw", /* … but then exclude *.confext.raw again */
".extra/sysext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
&cpio_target_sysext,
/* tpm_pcr= */ TPM2_PCR_SYSEXTS,
u"System extension initrd",
initrds + INITRD_SYSEXT,
@@ -885,9 +851,7 @@ static void generate_sidecar_initrds(
u"\\loader\\extensions",
u".raw", /* as above */
u".confext.raw",
".extra/global_sysext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
&cpio_target_global_sysext,
/* tpm_pcr= */ TPM2_PCR_SYSEXTS,
u"Global system extension initrd",
initrds + INITRD_GLOBAL_SYSEXT,
@@ -898,9 +862,7 @@ static void generate_sidecar_initrds(
/* dropin_dir= */ NULL,
u".confext.raw",
/* exclude_suffix= */ NULL,
".extra/confext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
&cpio_target_confext,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Configuration extension initrd",
initrds + INITRD_CONFEXT,
@@ -911,9 +873,7 @@ static void generate_sidecar_initrds(
u"\\loader\\extensions",
u".confext.raw",
/* exclude_suffix= */ NULL,
".extra/global_confext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
&cpio_target_global_confext,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Global configuration extension initrd",
initrds + INITRD_GLOBAL_CONFEXT,
@@ -964,10 +924,8 @@ static void generate_embedded_initrds(
(void) pack_cpio_literal(
(const uint8_t*) loaded_image->ImageBase + sections[t->section].memory_offset,
sections[t->section].memory_size,
".extra",
&cpio_target_meta,
t->filename,
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
/* tpm_pcr= */ UINT32_MAX,
/* tpm_description= */ NULL,
initrds + t->initrd_index,
@@ -988,10 +946,8 @@ static void generate_boot_secret_initrd(
(void) pack_cpio_literal(
boot_secret,
BOOT_SECRET_SIZE,
".extra",
&cpio_target_meta_secret,
u"boot-secret",
/* dir_mode= */ 0555,
/* access_mode= */ 0400,
/* tpm_pcr= */ UINT32_MAX,
/* tpm_description= */ NULL,
initrds + INITRD_BOOT_SECRET,
@@ -1309,6 +1265,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
install_addon_devicetrees(&dt_state, dt_addons, n_dt_addons, &parameters_measured);
/* Generate & find all initrds */
acquire_previous_initrd(initrds);
generate_sidecar_initrds(loaded_image, initrds, &parameters_measured, &sysext_measured, &confext_measured);
generate_embedded_initrds(loaded_image, sections, initrds);
generate_boot_secret_initrd(boot_secret, initrds);
@@ -1319,9 +1276,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
* 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 */
* 3. Previous initrds
* 4. UKI initrd
* 5. Generated initrds
* 6. initrd addons */
measure_and_append_ucode_addons(&all_initrds, &n_all_initrds, ucode_addons, n_ucode_addons, &parameters_measured);
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);