diff options
-rw-r--r-- | man/systemd-stub.xml | 24 | ||||
-rw-r--r-- | src/boot/efi/cpio.c | 15 | ||||
-rw-r--r-- | src/boot/efi/cpio.h | 4 | ||||
-rw-r--r-- | src/boot/efi/stub.c | 47 |
4 files changed, 62 insertions, 28 deletions
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml index 2a32e05bcc..b1983b4927 100644 --- a/man/systemd-stub.xml +++ b/man/systemd-stub.xml @@ -27,6 +27,9 @@ <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> @@ -78,13 +81,14 @@ <title>Companion Files</title> <para>The <command>systemd-stub</command> 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 - <command>cpio</command> initrd archives from them, and passes them to the kernel. Specifically:</para> + 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 + <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> + <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, @@ -94,16 +98,22 @@ details on encrypted credentials. The generated <command>cpio</command> archive is measured into TPM PCR 4 (if a TPM is present)</para></listitem> - <listitem><para>Similar, files <filename><replaceable>foo</replaceable>.efi.extra.d/*.raw</filename> - are packed up as <command>cpio</command> archive and placed in the <filename>/.extra/sysext/</filename> + <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 8 (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 4 (if a TPM is present)</para></listitem> </itemizedlist> - <para>Both mechanisms may be used to parameterize and extend trusted (i.e. signed), immutable initrd + <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 diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c index d7dd50fc8f..be0708aec4 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 7a2331e0c8..a272d28929 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 c99b3b7d6d..0b1f276c41 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) { |