Merge pull request #29940 from poettering/stub-confext-pickup

stub/sysext: pick up confexts from ESP, too
This commit is contained in:
Lennart Poettering
2024-01-03 17:40:36 +01:00
committed by GitHub
12 changed files with 132 additions and 36 deletions
+54 -12
View File
@@ -32,6 +32,8 @@
<member><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.addon.efi</filename></member>
<member><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.cred</filename></member>
<member><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.raw</filename></member>
<member><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.sysext.raw</filename></member>
<member><filename><replaceable>ESP</replaceable>/.../<replaceable>foo</replaceable>.efi.extra.d/*.confext.raw</filename></member>
<member><filename><replaceable>ESP</replaceable>/loader/addons/*.addon.efi</filename></member>
<member><filename><replaceable>ESP</replaceable>/loader/credentials/*.cred</filename></member>
</simplelist></para>
@@ -153,14 +155,28 @@
details on encrypted credentials. The generated <command>cpio</command> archive is measured into TPM
PCR 12 (if a TPM is present).</para></listitem>
<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
<listitem><para>Similarly, files
<filename><replaceable>foo</replaceable>.efi.extra.d/*.sysext.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 13 (if a TPM is present).</para></listitem>
<!-- Note: the actual suffix we look for for sysexts is just *.raw (not *.sysext.raw), for
compatibility reasons with old versions. But we want people to name their system extensions
properly, hence we document the *.sysext.raw suffix only. -->
<listitem><para>Similarly, files
<filename><replaceable>foo</replaceable>.efi.extra.d/*.confext.raw</filename> are packed up in a
<command>cpio</command> archive and placed in the <filename>/.extra/confext/</filename> directory in
the initrd file hierarchy. This is supposed to be used to pass additional configuration extension
images to the initrd. See
<citerefentry><refentrytitle>systemd-confext</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
details on configuration extension images. The generated <command>cpio</command> archive containing
these system extension images is measured into TPM PCR 12 (if a TPM is present).</para></listitem>
<listitem><para>Similarly, files
<filename><replaceable>foo</replaceable>.efi.extra.d/*.addon.efi</filename> are loaded and verified as
PE binaries, and a <literal>.cmdline</literal> section is parsed from them. Addons are supposed to be
@@ -218,9 +234,10 @@
<para>Also note that the Linux kernel will measure all initrds it receives into TPM PCR 9. This means
every type of initrd will be measured two or three times: the initrd embedded in the kernel image will be
measured to PCR 4, PCR 9 and PCR 11; the initrd synthesized from credentials will be measured to both PCR
9 and PCR 12; the initrd synthesized from system extensions will be measured to both PCR 4 and PCR
9. Let's summarize the OS resources and the PCRs they are measured to:</para>
measured to PCR 4, PCR 9 and PCR 11; the initrd synthesized from credentials (and the one synthesized
from configuration extensions) will be measured to both PCR 9 and PCR 12; the initrd synthesized from
system extensions will be measured to both PCR 4 and PCR 9. Let's summarize the OS resources and the PCRs
they are measured to:</para>
<table>
<title>OS Resource PCR Summary</title>
@@ -291,6 +308,11 @@
<entry>System Extensions (synthesized initrd from companion files)</entry>
<entry>9 + 13</entry>
</row>
<row>
<entry>Configuration Extensions (synthesized initrd from companion files)</entry>
<entry>9 + 12</entry>
</row>
</tbody>
</tgroup>
</table>
@@ -371,13 +393,24 @@
<varlistentry>
<term><varname>StubPcrInitRDSysExts</varname></term>
<listitem><para>The PCR register index the systemd extensions for the initrd, which are picked up
from the file system the kernel image is located on. Formatted as decimal ASCII string (e.g.
<listitem><para>The PCR register index the system extensions for the initrd, which are picked up from
the file system the kernel image is located on. Formatted as decimal ASCII string (e.g.
<literal>13</literal>). This variable is set if a measurement was successfully completed, and remains
unset otherwise.</para>
<xi:include href="version-info.xml" xpointer="v252"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>StubPcrInitRDConfExts</varname></term>
<listitem><para>The PCR register index the configuration extensions for the initrd, which are picked
up from the file system the kernel image is located on. Formatted as decimal ASCII string (e.g.
<literal>12</literal>). This variable is set if a measurement was successfully completed, and remains
unset otherwise.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
</variablelist>
<para>Note that some of the variables above may also be set by the boot loader. The stub will only set
@@ -422,14 +455,23 @@
</varlistentry>
<varlistentry>
<term><filename>/.extra/sysext/*.raw</filename></term>
<listitem><para>System extension image files (suffix <literal>.raw</literal>) that are placed next to
the unified kernel image (as described above) are copied into the
<term><filename>/.extra/sysext/*.sysext.raw</filename></term>
<listitem><para>System extension image files (suffix <literal>.sysext.raw</literal>) that are placed
next to the unified kernel image (as described above) are copied into the
<filename>/.extra/sysext/</filename> directory in the initrd execution environment.</para>
<xi:include href="version-info.xml" xpointer="v252"/></listitem>
</varlistentry>
<varlistentry>
<term><filename>/.extra/confext/*.confext.raw</filename></term>
<listitem><para>Configuration extension image files (suffix <literal>.confext.raw</literal>) that are
placed next to the unified kernel image (as described above) are copied into the
<filename>/.extra/confext/</filename> directory in the initrd execution environment.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<varlistentry>
<term><filename>/.extra/tpm2-pcr-signature.json</filename></term>
<listitem><para>The TPM2 PCR signature JSON object included in the <literal>.pcrsig</literal> PE
+2
View File
@@ -94,6 +94,8 @@ int verb_image_policy(int argc, char *argv[], void *userdata) {
p = &image_policy_sysext_strict;
else if (streq(argv[i], "@confext"))
p = &image_policy_confext;
else if (streq(argv[i], "@confext-strict"))
p = &image_policy_confext_strict;
else if (streq(argv[i], "@container"))
p = &image_policy_container;
else if (streq(argv[i], "@service"))
+9 -8
View File
@@ -374,14 +374,15 @@ int verb_status(int argc, char *argv[], void *userdata) {
uint64_t flag;
const char *name;
} stub_flags[] = {
{ EFI_STUB_FEATURE_REPORT_BOOT_PARTITION, "Stub sets ESP information" },
{ EFI_STUB_FEATURE_PICK_UP_CREDENTIALS, "Picks up credentials from boot partition" },
{ EFI_STUB_FEATURE_PICK_UP_SYSEXTS, "Picks up system extension images from boot partition" },
{ EFI_STUB_FEATURE_THREE_PCRS, "Measures kernel+command line+sysexts" },
{ EFI_STUB_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
{ EFI_STUB_FEATURE_CMDLINE_ADDONS, "Pick up .cmdline from addons" },
{ EFI_STUB_FEATURE_CMDLINE_SMBIOS, "Pick up .cmdline from SMBIOS Type 11" },
{ EFI_STUB_FEATURE_DEVICETREE_ADDONS, "Pick up .dtb from addons" },
{ EFI_STUB_FEATURE_REPORT_BOOT_PARTITION, "Stub sets ESP information" },
{ EFI_STUB_FEATURE_PICK_UP_CREDENTIALS, "Picks up credentials from boot partition" },
{ EFI_STUB_FEATURE_PICK_UP_SYSEXTS, "Picks up system extension images from boot partition" },
{ EFI_STUB_FEATURE_PICK_UP_CONFEXTS, "Picks up configuration extension images from boot partition" },
{ EFI_STUB_FEATURE_THREE_PCRS, "Measures kernel+command line+sysexts" },
{ EFI_STUB_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
{ EFI_STUB_FEATURE_CMDLINE_ADDONS, "Pick up .cmdline from addons" },
{ EFI_STUB_FEATURE_CMDLINE_SMBIOS, "Pick up .cmdline from SMBIOS Type 11" },
{ EFI_STUB_FEATURE_DEVICETREE_ADDONS, "Pick up .dtb from addons" },
};
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
sd_id128_t loader_part_uuid = SD_ID128_NULL;
+3
View File
@@ -305,6 +305,7 @@ 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,
@@ -367,6 +368,8 @@ EFI_STATUS pack_cpio(
continue;
if (match_suffix && !endswith_no_case(dirent->FileName, match_suffix))
continue;
if (exclude_suffix && endswith_no_case(dirent->FileName, exclude_suffix))
continue;
if (!is_ascii(dirent->FileName))
continue;
if (strlen16(dirent->FileName) > 255) /* Max filename size on Linux */
+1
View File
@@ -8,6 +8,7 @@ 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,
+31 -8
View File
@@ -91,6 +91,7 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
EFI_STUB_FEATURE_REPORT_BOOT_PARTITION | /* We set LoaderDevicePartUUID */
EFI_STUB_FEATURE_PICK_UP_CREDENTIALS | /* We pick up credentials from the boot partition */
EFI_STUB_FEATURE_PICK_UP_SYSEXTS | /* We pick up system extensions from the boot partition */
EFI_STUB_FEATURE_PICK_UP_CONFEXTS | /* We pick up configuration extensions from the boot partition */
EFI_STUB_FEATURE_THREE_PCRS | /* We can measure kernel image, parameters and sysext */
EFI_STUB_FEATURE_RANDOM_SEED | /* We pass a random seed to the kernel */
EFI_STUB_FEATURE_CMDLINE_ADDONS | /* We pick up .cmdline addons */
@@ -497,8 +498,8 @@ static EFI_STATUS load_addons(
}
static EFI_STATUS run(EFI_HANDLE image) {
_cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
_cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *confext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, confext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
void **dt_bases_addons_global = NULL, **dt_bases_addons_uki = NULL;
char16_t **dt_filenames_addons_global = NULL, **dt_filenames_addons_uki = NULL;
_cleanup_free_ size_t *dt_sizes_addons_global = NULL, *dt_sizes_addons_uki = NULL;
@@ -510,7 +511,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
_cleanup_free_ char16_t *cmdline = NULL, *cmdline_addons_global = NULL, *cmdline_addons_uki = NULL;
int sections_measured = -1, parameters_measured = -1;
_cleanup_free_ char *uname = NULL;
bool sysext_measured = false, m;
bool sysext_measured = false, confext_measured = false, m;
uint64_t loader_features = 0;
EFI_STATUS err;
@@ -660,8 +661,9 @@ static EFI_STATUS run(EFI_HANDLE image) {
export_variables(loaded_image);
if (pack_cpio(loaded_image,
NULL,
/* dropin_dir= */ NULL,
u".cred",
/* exclude_suffix= */ NULL,
".extra/credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
@@ -675,6 +677,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
if (pack_cpio(loaded_image,
u"\\loader\\credentials",
u".cred",
/* exclude_suffix= */ NULL,
".extra/global_credentials",
/* dir_mode= */ 0500,
/* access_mode= */ 0400,
@@ -686,8 +689,9 @@ static EFI_STATUS run(EFI_HANDLE image) {
parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
if (pack_cpio(loaded_image,
NULL,
u".raw",
/* 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,
@@ -698,6 +702,20 @@ static EFI_STATUS run(EFI_HANDLE image) {
&m) == EFI_SUCCESS)
sysext_measured = m;
if (pack_cpio(loaded_image,
/* dropin_dir= */ NULL,
u".confext.raw",
/* exclude_suffix= */ NULL,
".extra/confext",
/* dir_mode= */ 0555,
/* access_mode= */ 0444,
/* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
u"Configuration extension initrd",
&confext_initrd,
&confext_initrd_size,
&m) == EFI_SUCCESS)
confext_measured = m;
dt_size = szs[UNIFIED_SECTION_DTB];
dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_DTB] : 0;
@@ -728,6 +746,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
(void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG, 0);
if (sysext_measured)
(void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDSysExts", TPM2_PCR_SYSEXTS, 0);
if (confext_measured)
(void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDConfExts", TPM2_PCR_KERNEL_CONFIG, 0);
/* If the PCR signature was embedded in the PE image, then let's wrap it in a cpio and also pass it
* to the kernel, so that it can be read from /.extra/tpm2-pcr-signature.json. Note that this section
@@ -773,7 +793,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_INITRD] : 0;
_cleanup_pages_ Pages initrd_pages = {};
if (credential_initrd || global_credential_initrd || sysext_initrd || pcrsig_initrd || pcrpkey_initrd) {
if (credential_initrd || global_credential_initrd || sysext_initrd || confext_initrd || pcrsig_initrd || pcrpkey_initrd) {
/* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
err = combine_initrd(
initrd_base, initrd_size,
@@ -781,6 +801,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
credential_initrd,
global_credential_initrd,
sysext_initrd,
confext_initrd,
pcrsig_initrd,
pcrpkey_initrd,
},
@@ -788,10 +809,11 @@ static EFI_STATUS run(EFI_HANDLE image) {
credential_initrd_size,
global_credential_initrd_size,
sysext_initrd_size,
confext_initrd_size,
pcrsig_initrd_size,
pcrpkey_initrd_size,
},
5,
6,
&initrd_pages, &initrd_size);
if (err != EFI_SUCCESS)
return err;
@@ -802,6 +824,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
credential_initrd = mfree(credential_initrd);
global_credential_initrd = mfree(global_credential_initrd);
sysext_initrd = mfree(sysext_initrd);
confext_initrd = mfree(confext_initrd);
pcrsig_initrd = mfree(pcrsig_initrd);
pcrpkey_initrd = mfree(pcrpkey_initrd);
}
+1
View File
@@ -33,6 +33,7 @@
#define EFI_STUB_FEATURE_CMDLINE_ADDONS (UINT64_C(1) << 5)
#define EFI_STUB_FEATURE_CMDLINE_SMBIOS (UINT64_C(1) << 6)
#define EFI_STUB_FEATURE_DEVICETREE_ADDONS (UINT64_C(1) << 7)
#define EFI_STUB_FEATURE_PICK_UP_CONFEXTS (UINT64_C(1) << 8)
typedef enum SecureBootMode {
SECURE_BOOT_UNSUPPORTED,
+8 -3
View File
@@ -75,15 +75,20 @@ static const char* const image_search_path[_IMAGE_CLASS_MAX] = {
"/usr/lib/confexts\0",
};
/* Inside the initrd, use a slightly different set of search path (i.e. include .extra/sysext in extension
* search dir) */
/* Inside the initrd, use a slightly different set of search path (i.e. include .extra/sysext/ and
* .extra/confext/ in extension search dir) */
static const char* const image_search_path_initrd[_IMAGE_CLASS_MAX] = {
/* (entries that aren't listed here will get the same search path as for the non initrd-case) */
[IMAGE_SYSEXT] = "/etc/extensions\0" /* only place symlinks here */
"/run/extensions\0" /* and here too */
"/var/lib/extensions\0" /* the main place for images */
"/.extra/sysext\0" /* put sysext picked up by systemd-stub last, since not trusted */
"/.extra/sysext\0", /* put sysext picked up by systemd-stub last, since not trusted */
[IMAGE_CONFEXT] = "/run/confexts\0" /* only place symlinks here */
"/var/lib/confexts\0" /* the main place for images */
"/usr/local/lib/confexts\0"
"/.extra/confext\0", /* put confext picked up by systemd-stub last, since not trusted */
};
static const char* image_class_suffix_table[_IMAGE_CLASS_MAX] = {
+8
View File
@@ -726,6 +726,14 @@ const ImagePolicy image_policy_confext = {
.default_flags = PARTITION_POLICY_IGNORE,
};
const ImagePolicy image_policy_confext_strict = {
.n_policies = 1,
.policies = {
{ PARTITION_ROOT, PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT },
},
.default_flags = PARTITION_POLICY_IGNORE,
};
const ImagePolicy image_policy_container = {
/* For systemd-nspawn containers we use all partitions, with the exception of swap */
.n_policies = 8,
+4 -3
View File
@@ -58,9 +58,10 @@ struct ImagePolicy {
extern const ImagePolicy image_policy_allow;
extern const ImagePolicy image_policy_deny;
extern const ImagePolicy image_policy_ignore;
extern const ImagePolicy image_policy_sysext; /* No verity required */
extern const ImagePolicy image_policy_sysext_strict; /* Signed verity required */
extern const ImagePolicy image_policy_confext; /* No verity required */
extern const ImagePolicy image_policy_sysext; /* No verity required */
extern const ImagePolicy image_policy_sysext_strict; /* Signed verity required */
extern const ImagePolicy image_policy_confext; /* No verity required */
extern const ImagePolicy image_policy_confext_strict; /* Signed verity required */
extern const ImagePolicy image_policy_container;
extern const ImagePolicy image_policy_service;
extern const ImagePolicy image_policy_host;
+10 -2
View File
@@ -659,8 +659,16 @@ static const ImagePolicy *pick_image_policy(const Image *img) {
* picked up from an untrusted ESP. Thus, require a stricter policy by default for them. (For the
* other directories we assume the appropriate level of trust was already established already. */
if (in_initrd() && path_startswith(img->path, "/.extra/sysext/"))
return &image_policy_sysext_strict;
if (in_initrd()) {
if (path_startswith(img->path, "/.extra/sysext/"))
return &image_policy_sysext_strict;
if (path_startswith(img->path, "/.extra/confext/"))
return &image_policy_confext_strict;
/* Better safe than sorry, refuse everything else passed in via the untrusted /.extra/ dir */
if (path_startswith(img->path, "/.extra/"))
return &image_policy_deny;
}
return image_class_info[img->class].default_image_policy;
}
+1
View File
@@ -79,6 +79,7 @@ TEST_RET(test_image_policy_to_string) {
test_policy(&image_policy_sysext, "sysext");
test_policy(&image_policy_sysext_strict, "sysext-strict");
test_policy(&image_policy_confext, "confext");
test_policy(&image_policy_confext_strict, "confext-strict");
test_policy(&image_policy_container, "container");
test_policy(&image_policy_host, "host");
test_policy(&image_policy_service, "service");