summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-10-17 14:50:56 +0200
committerLennart Poettering <lennart@poettering.net>2023-01-17 09:42:16 +0100
commit6c51b49ce0892ff923233a6031add4877100f5b0 (patch)
tree454025e5aa2a5bf4dd3d4461d91f1e007e87eb50
parentgenerators: optionally, measure file systems at boot (diff)
downloadsystemd-6c51b49ce0892ff923233a6031add4877100f5b0.tar.xz
systemd-6c51b49ce0892ff923233a6031add4877100f5b0.zip
tpm2: add common helper for checking if we are running on UKI with TPM measurements
Let's introduce a common implementation of a function that checks whether we are booted on a kernel with systemd-stub that has TPM PCR measurements enabled. Do our own userspace measurements only if we detect that. PCRs are scarce and most likely there are projects which already make use of them in other ways. Hence, instead of blindly stepping into their territory let's conditionalize things so that people have to explicitly buy into our PCR assignments before we start measuring things into them. Specifically bind everything to an UKI that reported measurements. This was previously already implemented in systemd-pcrphase, but with this change we expand this to all tools that process PCR measurement settings. The env var to override the check is renamed to SYSTEMD_FORCE_MEASURE, to make it more generic (since we'll use it at multiple places now). This is not a compat break, since the original env var for that was not included in any stable release yet.
-rw-r--r--docs/ENVIRONMENT.md9
-rw-r--r--src/boot/pcrphase.c38
-rw-r--r--src/cryptsetup/cryptsetup.c9
-rw-r--r--src/fstab-generator/fstab-generator.c12
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c10
-rw-r--r--src/shared/efi-loader.c39
-rw-r--r--src/shared/efi-loader.h2
7 files changed, 80 insertions, 39 deletions
diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md
index 2b751d9d53..ef0141e1a6 100644
--- a/docs/ENVIRONMENT.md
+++ b/docs/ENVIRONMENT.md
@@ -506,7 +506,10 @@ SYSTEMD_HOME_DEBUG_SUFFIX=foo \
journal. Note that journal files in compact mode are limited to 4G to allow use of
32-bit offsets. Enabled by default.
-`systemd-pcrphase`:
+`systemd-pcrphase`, `systemd-cryptsetup`:
-* `$SYSTEMD_PCRPHASE_STUB_VERIFY` – Takes a boolean. If false the requested
- measurement is done even if no EFI stub usage was reported via EFI variables.
+* `$SYSTEMD_FORCE_MEASURE=1` — If set, force measuring of resources (which are
+ marked for measurement) even if not booted on a kernel equipped with
+ systemd-stub. Normally, requested measurement of resources is conditionalized
+ on kernels that have booted with `systemd-stub`. With this environment
+ variable the test for that my be bypassed, for testing purposes.
diff --git a/src/boot/pcrphase.c b/src/boot/pcrphase.c
index 70c919b0f5..003e0b8ad8 100644
--- a/src/boot/pcrphase.c
+++ b/src/boot/pcrphase.c
@@ -9,15 +9,14 @@
#include "blockdev-util.h"
#include "build.h"
#include "chase-symlinks.h"
+#include "efi-loader.h"
#include "efivars.h"
-#include "env-util.h"
#include "escape.h"
#include "fd-util.h"
#include "main-func.h"
#include "mountpoint-util.h"
#include "openssl-util.h"
#include "parse-argument.h"
-#include "parse-util.h"
#include "pretty-print.h"
#include "tpm-pcr.h"
#include "tpm2-util.h"
@@ -241,9 +240,9 @@ static int get_file_system_word(
}
static int run(int argc, char *argv[]) {
- _cleanup_free_ char *joined = NULL, *pcr_string = NULL, *word = NULL;
_cleanup_(tpm2_context_destroy) struct tpm2_context c = {};
- unsigned target_pcr_nr, efi_pcr_nr;
+ _cleanup_free_ char *joined = NULL, *word = NULL;
+ unsigned target_pcr_nr;
size_t length;
int r;
@@ -334,32 +333,13 @@ static int run(int argc, char *argv[]) {
length = strlen(word);
- int b = getenv_bool("SYSTEMD_PCRPHASE_STUB_VERIFY");
- if (b < 0 && b != -ENXIO)
- log_warning_errno(b, "Unable to parse $SYSTEMD_PCRPHASE_STUB_VERIFY value, ignoring.");
-
/* Skip logic if sd-stub is not used, after all PCR 11 might have a very different purpose then. */
- r = efi_get_variable_string(EFI_LOADER_VARIABLE(StubPcrKernelImage), &pcr_string);
- if (r == -ENOENT) {
- if (b != 0) {
- log_info("Kernel stub did not measure kernel image into PCR %u, skipping measurement.", TPM_PCR_INDEX_KERNEL_IMAGE);
- return EXIT_SUCCESS;
- } else
- log_notice("Kernel stub did not measure kernel image into PCR %u, but told to measure anyway, hence proceeding.", TPM_PCR_INDEX_KERNEL_IMAGE);
- } else if (r < 0)
- return log_error_errno(r, "Failed to read StubPcrKernelImage EFI variable: %m");
- else {
- /* Let's validate that the stub announced PCR 11 as we expected. */
- r = safe_atou(pcr_string, &efi_pcr_nr);
- if (r < 0)
- return log_error_errno(r, "Failed to parse StubPcrKernelImage EFI variable: %s", pcr_string);
- if (efi_pcr_nr != TPM_PCR_INDEX_KERNEL_IMAGE) {
- if (b != 0)
- return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Kernel stub measured kernel image into PCR %u, which is different than expected %u.", efi_pcr_nr, TPM_PCR_INDEX_KERNEL_IMAGE);
- else
- log_notice("Kernel stub measured kernel image into PCR %u, which is different than expected %u, but told to measure anyway, hence proceeding.", efi_pcr_nr, TPM_PCR_INDEX_KERNEL_IMAGE);
- } else
- log_debug("Kernel stub reported same PCR %u as we want to use, proceeding.", TPM_PCR_INDEX_KERNEL_IMAGE);
+ r = efi_stub_measured();
+ if (r < 0)
+ return log_error_errno(r, "Failed to detect if we are running on a kernel image with TPM measurement enabled: %m");
+ if (r == 0) {
+ log_info("Kernel stub did not measure kernel image into PCR %u, skipping userspace measurement, too.", TPM_PCR_INDEX_KERNEL_IMAGE);
+ return EXIT_SUCCESS;
}
r = dlopen_tpm2();
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 5efce63a38..2c9d416734 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -19,6 +19,7 @@
#include "cryptsetup-util.h"
#include "device-util.h"
#include "efi-api.h"
+#include "efi-loader.h"
#include "env-util.h"
#include "escape.h"
#include "fileio.h"
@@ -827,6 +828,14 @@ static int measure_volume_key(
return 0;
}
+ r = efi_stub_measured();
+ if (r < 0)
+ return log_warning_errno(r, "Failed to detect if we are running on a kernel image with TPM measurement enabled: %m");
+ if (r == 0) {
+ log_debug("Kernel stub did not measure kernel image into the expected PCR, skipping userspace measurement, too.");
+ return 0;
+ }
+
#if HAVE_TPM2
r = dlopen_tpm2();
if (r < 0)
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 4b763bc247..ed34e0a32f 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -8,6 +8,7 @@
#include "bus-error.h"
#include "bus-locator.h"
#include "chase-symlinks.h"
+#include "efi-loader.h"
#include "fd-util.h"
#include "fileio.h"
#include "fstab-util.h"
@@ -529,9 +530,16 @@ static int add_mount(
}
if (flags & MOUNT_PCRFS) {
- r = generator_hook_up_pcrfs(dest, where, target_unit);
+ r = efi_stub_measured();
if (r < 0)
- return r;
+ log_warning_errno(r, "Failed to detect if we are running on a kernel image with TPM measurement enabled, assuming not: %m");
+ else if (r == 0)
+ log_debug("Kernel stub did not measure kernel image into PCR, skipping userspace measurement, too.");
+ else {
+ r = generator_hook_up_pcrfs(dest, where, target_unit);
+ if (r < 0)
+ return r;
+ }
}
if (!FLAGS_SET(flags, MOUNT_AUTOMOUNT)) {
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 63bb2a3cbb..9b11318017 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -102,11 +102,11 @@ static int add_cryptsetup(
* assignment, under the assumption that people who are fine to use sd-stub with its PCR
* assignments are also OK with our PCR 15 use here. */
- r = efi_get_variable(EFI_LOADER_VARIABLE(StubPcrKernelImage), NULL, NULL, NULL); /* we don't actually care which PCR the UKI used for itself */
- if (r == -ENOENT)
- log_debug_errno(r, "Will not measure volume key of volume '%s', because not booted via systemd-stub with measurements enabled.", id);
- else if (r < 0)
- log_debug_errno(r, "Failed to determine whether booted via systemd-stub with measurements enabled, ignoring: %m");
+ r = efi_stub_measured();
+ if (r < 0)
+ log_warning_errno(r, "Failed to determine whether booted via systemd-stub with measurements enabled, ignoring: %m");
+ else if (r == 0)
+ log_debug("Will not measure volume key of volume '%s', because not booted via systemd-stub with measurements enabled.", id);
else if (!strextend_with_separator(&options, ",", "tpm2-measure-pcr=yes"))
return log_oom();
}
diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c
index 1340412cda..621fa082ba 100644
--- a/src/shared/efi-loader.c
+++ b/src/shared/efi-loader.c
@@ -2,10 +2,12 @@
#include "alloc-util.h"
#include "efi-loader.h"
+#include "env-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "strv.h"
+#include "tpm-pcr.h"
#include "utf8.h"
#if ENABLE_EFI
@@ -236,6 +238,43 @@ int efi_stub_get_features(uint64_t *ret) {
return 0;
}
+int efi_stub_measured(void) {
+ _cleanup_free_ char *pcr_string = NULL;
+ unsigned pcr_nr;
+ int r;
+
+ /* Checks if we are booted on a kernel with sd-stub which measured the kernel into PCR 11. Or in
+ * other words, if we are running on a TPM enabled UKI.
+ *
+ * Returns == 0 and > 0 depending on the result of the test. Returns -EREMOTE if we detected a stub
+ * being used, but it measured things into a different PCR than we are configured for in
+ * userspace. (i.e. we expect PCR 11 being used for this by both sd-stub and us) */
+
+ r = getenv_bool_secure("SYSTEMD_FORCE_MEASURE"); /* Give user a chance to override the variable test,
+ * for debugging purposes */
+ if (r >= 0)
+ return r;
+ if (r != -ENXIO)
+ log_debug_errno(r, "Failed to parse $SYSTEMD_FORCE_MEASURE, ignoring: %m");
+
+ if (!is_efi_boot())
+ return 0;
+
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE(StubPcrKernelImage), &pcr_string);
+ if (r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return r;
+
+ r = safe_atou(pcr_string, &pcr_nr);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse StubPcrKernelImage EFI variable: %s", pcr_string);
+ if (pcr_nr != TPM_PCR_INDEX_KERNEL_IMAGE)
+ return log_debug_errno(SYNTHETIC_ERRNO(EREMOTE), "Kernel stub measured kernel image into PCR %u, which is different than expected %u.", pcr_nr, TPM_PCR_INDEX_KERNEL_IMAGE);
+
+ return 1;
+}
+
int efi_loader_get_config_timeout_one_shot(usec_t *ret) {
_cleanup_free_ char *v = NULL;
static struct stat cache_stat = {};
diff --git a/src/shared/efi-loader.h b/src/shared/efi-loader.h
index 84968869ab..56ccdee9c1 100644
--- a/src/shared/efi-loader.h
+++ b/src/shared/efi-loader.h
@@ -18,6 +18,8 @@ int efi_loader_get_entries(char ***ret);
int efi_loader_get_features(uint64_t *ret);
int efi_stub_get_features(uint64_t *ret);
+int efi_stub_measured(void);
+
int efi_loader_get_config_timeout_one_shot(usec_t *ret);
int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat);