]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
stub: Load credentials from \loader\credentials\*.cred 21570/head
authorAdrian Vovk <adrianvovk@gmail.com>
Wed, 8 Dec 2021 02:21:40 +0000 (21:21 -0500)
committerAdrian Vovk <adrianvovk@gmail.com>
Fri, 10 Dec 2021 20:56:33 +0000 (15:56 -0500)
Some types of credentials that a user would want to pass
into the initrd do not depend on the specific kernel/initrd
version. For instance, this can include SSH keys, rootfs
encryption keys, dm-integrity keys, and so on. This
introduces a directory where such credentials can be placed
so that any kernel image will load them

man/systemd-stub.xml
src/boot/efi/cpio.c
src/boot/efi/cpio.h
src/boot/efi/stub.c

index 2a32e05bcc36ab0f8014568e2ebdcbcf9c528e8e..b1983b4927e0f362fb73039d9727199c9c9b722e 100644 (file)
@@ -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>
     <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,
       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
index d4c870284bb62ee1e8bb3c8eab7f5ab746611d5d..be0708aec43dd70b4d5653c3d728bf6c7c6c4bd6 100644 (file)
@@ -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";
 
@@ -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;
index 7a2331e0c8eff085579c10d5df643dcb6a855ae1..a272d289298322815a8b93b543dfd25389a8bb50 100644 (file)
@@ -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);
+
index c99b3b7d6d6d08f94d2f556ae13271e11ba79233..0b1f276c4167683f17bc4967bf7ba6402787e0af 100644 (file)
@@ -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) {