diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index 2a32e05bcc3..b1983b4927e 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -27,6 +27,9 @@
/usr/lib/systemd/boot/efi/linuxx64.efi.stub
/usr/lib/systemd/boot/efi/linuxia32.efi.stub
/usr/lib/systemd/boot/efi/linuxaa64.efi.stub
+ ESP/.../foo.efi.extra.d/*.cred
+ ESP/.../foo.efi.extra.d/*.raw
+ ESP/loader/credentials/*.cred
@@ -78,13 +81,14 @@
Companion Files
The systemd-stub UEFI boot stub automatically collects two types of auxiliary
- companion files optionally placed in a drop-in directory next to the EFI binary and dynamically generates
- cpio initrd archives from them, and passes them to the kernel. Specifically:
+ companion files optionally placed in drop-in directories on the same partition as the EFI binary,
+ dynamically generates cpio initrd archives from them, and passes them to the kernel.
+ Specifically:
- For a kernel binary called foo.efi it
+ For a kernel binary called foo.efi, it
will look for files with the .cred suffix in a directory named
- foo.efi.extra.d/, next to it. A cpio
+ foo.efi.extra.d/ next to it. A cpio
archive is generated from all files found that way, placing them in the
/.extra/credentials/ 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,
@@ -94,16 +98,22 @@
details on encrypted credentials. The generated cpio archive is measured into TPM
PCR 4 (if a TPM is present)
- Similar, files foo.efi.extra.d/*.raw
- are packed up as cpio archive and placed in the /.extra/sysext/
+ Similarly, files foo.efi.extra.d/*.raw
+ are packed up in a cpio archive and placed in the /.extra/sysext/
directory in the initrd file hierarchy. This is supposed to be used to pass additional system extension
images to the initrd. See
systemd-sysext8 for
details on system extension images. The generated cpio archive containing these
system extension images is measured into TPM PCR 8 (if a TPM is present).
+
+ Files /loader/credentials/*.cred are packed up in a
+ cpio archive and placed in the /.extra/global_credentials/
+ 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 cpio archive is
+ measured into TPM PCR 4 (if a TPM is present)
- Both mechanisms may be used to parameterize and extend trusted (i.e. signed), immutable initrd
+ 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 systemd-creds encrypt -T (see
diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c
index d7dd50fc8fa..be0708aec43 100644
--- a/src/boot/efi/cpio.c
+++ b/src/boot/efi/cpio.c
@@ -4,8 +4,6 @@
#include "measure.h"
#include "util.h"
-#define EXTRA_DIR_SUFFIX L".extra.d"
-
static CHAR8* write_cpio_word(CHAR8 *p, UINT32 v) {
static const char hex[] = "0123456789abcdef";
@@ -34,7 +32,7 @@ static CHAR8* mangle_filename(CHAR8 *p, const CHAR16 *f) {
*(w++) = *f;
}
- *w = 0;
+ *(w++) = 0;
return w;
}
@@ -138,7 +136,7 @@ static EFI_STATUS pack_cpio_one(
a = write_cpio_word(a, 0); /* minor(dev) */
a = write_cpio_word(a, 0); /* major(rdev) */
a = write_cpio_word(a, 0); /* minor(rdev) */
- a = write_cpio_word(a, target_dir_prefix_size + fname_size + 1); /* fname size */
+ a = write_cpio_word(a, target_dir_prefix_size + fname_size + 2); /* fname size */
a = write_cpio_word(a, 0); /* "crc" */
CopyMem(a, target_dir_prefix, target_dir_prefix_size);
@@ -308,6 +306,7 @@ static EFI_STATUS pack_cpio_trailer(
EFI_STATUS pack_cpio(
EFI_LOADED_IMAGE *loaded_image,
+ const CHAR16 *dropin_dir,
const CHAR16 *match_suffix,
const CHAR8 *target_dir_prefix,
UINT32 dir_mode,
@@ -319,7 +318,7 @@ EFI_STATUS pack_cpio(
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE root = NULL, extra_dir = NULL;
UINTN dirent_size = 0, buffer_size = 0, n_items = 0, n_allocated = 0;
- _cleanup_freepool_ CHAR16 *extra_dir_path = NULL;
+ _cleanup_freepool_ CHAR16 *rel_dropin_dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *dirent = NULL;
_cleanup_(strv_freep) CHAR16 **items = NULL;
_cleanup_freepool_ void *buffer = NULL;
@@ -335,8 +334,10 @@ EFI_STATUS pack_cpio(
if (!root)
return log_error_status_stall(EFI_LOAD_ERROR, L"Unable to open root directory.");
- extra_dir_path = xpool_print(L"%D" EXTRA_DIR_SUFFIX, loaded_image->FilePath);
- err = open_directory(root, extra_dir_path, &extra_dir);
+ if (!dropin_dir)
+ dropin_dir = rel_dropin_dir = xpool_print(L"%D.extra.d", loaded_image->FilePath);
+
+ err = open_directory(root, dropin_dir, &extra_dir);
if (err == EFI_NOT_FOUND) {
/* No extra subdir, that's totally OK */
*ret_buffer = NULL;
diff --git a/src/boot/efi/cpio.h b/src/boot/efi/cpio.h
index 7a2331e0c8e..a272d289298 100644
--- a/src/boot/efi/cpio.h
+++ b/src/boot/efi/cpio.h
@@ -5,11 +5,13 @@
EFI_STATUS pack_cpio(
EFI_LOADED_IMAGE *loaded_image,
+ const CHAR16 *dropin_dir,
const CHAR16 *match_suffix,
const CHAR8 *target_dir_prefix,
UINT32 dir_mode,
UINT32 access_mode,
- UINTN pcr,
+ UINTN tpm_pcr,
const CHAR16 *tpm_description,
void **ret_buffer,
UINTN *ret_buffer_size);
+
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index c99b3b7d6d6..0b1f276c416 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -20,6 +20,7 @@ _used_ _section_(".sdmagic") static const char magic[] = "#### LoaderInfo: syste
static EFI_STATUS combine_initrd(
EFI_PHYSICAL_ADDRESS initrd_base, UINTN initrd_size,
const void *credential_initrd, UINTN credential_initrd_size,
+ const void *global_credential_initrd, UINTN global_credential_initrd_size,
const void *sysext_initrd, UINTN sysext_initrd_size,
EFI_PHYSICAL_ADDRESS *ret_initrd_base, UINTN *ret_initrd_size) {
@@ -31,7 +32,7 @@ static EFI_STATUS combine_initrd(
assert(ret_initrd_base);
assert(ret_initrd_size);
- /* Combines three initrds into one, by simple concatenation in memory */
+ /* Combines four initrds into one, by simple concatenation in memory */
n = ALIGN_TO(initrd_size, 4); /* main initrd might not be padded yet */
if (credential_initrd) {
@@ -40,6 +41,12 @@ static EFI_STATUS combine_initrd(
n += credential_initrd_size;
}
+ if (global_credential_initrd) {
+ if (n > UINTN_MAX - global_credential_initrd_size)
+ return EFI_OUT_OF_RESOURCES;
+
+ n += global_credential_initrd_size;
+ }
if (sysext_initrd) {
if (n > UINTN_MAX - sysext_initrd_size)
return EFI_OUT_OF_RESOURCES;
@@ -76,6 +83,11 @@ static EFI_STATUS combine_initrd(
p += credential_initrd_size;
}
+ if (global_credential_initrd) {
+ CopyMem(p, global_credential_initrd, global_credential_initrd_size);
+ p += global_credential_initrd_size;
+ }
+
if (sysext_initrd) {
CopyMem(p, sysext_initrd, sysext_initrd_size);
p += sysext_initrd_size;
@@ -156,8 +168,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
};
UINTN cmdline_len = 0, linux_size, initrd_size, dt_size;
- UINTN credential_initrd_size = 0, sysext_initrd_size = 0;
- _cleanup_freepool_ void *credential_initrd = NULL, *sysext_initrd = NULL;
+ UINTN credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0;
+ _cleanup_freepool_ void *credential_initrd = NULL, *global_credential_initrd = NULL;
+ _cleanup_freepool_ void *sysext_initrd = NULL;
EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base;
_cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
EFI_LOADED_IMAGE *loaded_image;
@@ -213,6 +226,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
export_variables(loaded_image);
(void) pack_cpio(loaded_image,
+ NULL,
L".cred",
(const CHAR8*) ".extra/credentials",
/* dir_mode= */ 0500,
@@ -223,6 +237,18 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
&credential_initrd_size);
(void) pack_cpio(loaded_image,
+ L"\\loader\\credentials",
+ L".cred",
+ (const CHAR8*) ".extra/global_credentials",
+ /* dir_mode= */ 0500,
+ /* access_mode= */ 0400,
+ /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS,
+ L"Global credentials initrd",
+ &global_credential_initrd,
+ &global_credential_initrd_size);
+
+ (void) pack_cpio(loaded_image,
+ NULL,
L".raw",
(const CHAR8*) ".extra/sysext",
/* dir_mode= */ 0555,
@@ -241,26 +267,21 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
dt_size = szs[SECTION_DTB];
dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_DTB] : 0;
- if (credential_initrd || sysext_initrd) {
+ if (credential_initrd || global_credential_initrd || sysext_initrd) {
/* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
err = combine_initrd(
initrd_base, initrd_size,
credential_initrd, credential_initrd_size,
+ global_credential_initrd, global_credential_initrd_size,
sysext_initrd, sysext_initrd_size,
&initrd_base, &initrd_size);
if (EFI_ERROR(err))
return err;
/* Given these might be large let's free them explicitly, quickly. */
- if (credential_initrd) {
- FreePool(credential_initrd);
- credential_initrd = NULL;
- }
-
- if (sysext_initrd) {
- FreePool(sysext_initrd);
- sysext_initrd = NULL;
- }
+ credential_initrd = mfree(credential_initrd);
+ global_credential_initrd = mfree(global_credential_initrd);
+ sysext_initrd = mfree(sysext_initrd);
}
if (dt_size > 0) {