summaryrefslogtreecommitdiffstats
path: root/src/pcrlock
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-11-20 18:01:40 +0100
committerLennart Poettering <lennart@poettering.net>2024-01-22 14:40:10 +0100
commit985a261701cd3ddcbd2587febacc490a481a6b59 (patch)
tree48c37ca122e0eaf09f6e7fca0d9589dcf1ccdef2 /src/pcrlock
parentmkosi: Use authselect local profile if it exists (diff)
downloadsystemd-985a261701cd3ddcbd2587febacc490a481a6b59.tar.xz
systemd-985a261701cd3ddcbd2587febacc490a481a6b59.zip
pcrlock: also write pcrlock policy as unencrypted credential to XBOOTLDR/ESP
Diffstat (limited to 'src/pcrlock')
-rw-r--r--src/pcrlock/pcrlock.c168
1 files changed, 156 insertions, 12 deletions
diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c
index e8c902c927..329153c65e 100644
--- a/src/pcrlock/pcrlock.c
+++ b/src/pcrlock/pcrlock.c
@@ -9,15 +9,18 @@
#include "ask-password-api.h"
#include "blockdev-util.h"
+#include "boot-entry.h"
#include "build.h"
#include "chase.h"
#include "color-util.h"
#include "conf-files.h"
+#include "creds-util.h"
#include "efi-api.h"
#include "env-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
+#include "find-esp.h"
#include "format-table.h"
#include "format-util.h"
#include "fs-util.h"
@@ -60,12 +63,15 @@ static TPM2_HANDLE arg_nv_index = 0;
static bool arg_recovery_pin = false;
static char *arg_policy_path = NULL;
static bool arg_force = false;
+static BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
+static char *arg_entry_token = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_components, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_pcrlock_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_location_start, freep);
STATIC_DESTRUCTOR_REGISTER(arg_location_end, freep);
STATIC_DESTRUCTOR_REGISTER(arg_policy_path, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
#define PCRLOCK_SECUREBOOT_POLICY_PATH "/var/lib/pcrlock.d/240-secureboot-policy.pcrlock.d/generated.pcrlock"
#define PCRLOCK_FIRMWARE_CODE_EARLY_PATH "/var/lib/pcrlock.d/250-firmware-code-early.pcrlock.d/generated.pcrlock"
@@ -4164,6 +4170,127 @@ static int remove_policy_file(const char *path) {
return 1;
}
+static int determine_boot_policy_file(char **ret) {
+ _cleanup_free_ char *path = NULL, *fn = NULL, *joined = NULL;
+ sd_id128_t machine_id;
+ int r;
+
+ assert(ret);
+
+ r = find_xbootldr_and_warn(
+ /* root= */ NULL,
+ /* path= */ NULL,
+ /* unprivileged_mode= */ false,
+ &path,
+ /* ret_uuid= */ NULL,
+ /* ret_devid= */ NULL);
+ if (r < 0) {
+ if (r != -ENOKEY)
+ return log_error_errno(r, "Failed to find XBOOTLDR partition: %m");
+
+ r = find_esp_and_warn(
+ /* root= */ NULL,
+ /* path= */ NULL,
+ /* unprivileged_mode= */ false,
+ &path,
+ /* ret_part= */ NULL,
+ /* ret_pstart= */ NULL,
+ /* ret_psize= */ NULL,
+ /* ret_uuid= */ NULL,
+ /* ret_devid= */ NULL);
+ if (r < 0) {
+ if (r != -ENOKEY)
+ return log_error_errno(r, "Failed to find ESP partition: %m");
+
+ *ret = NULL;
+ return 0; /* not found! */
+ }
+ }
+
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read machine ID: %m");
+
+ r = boot_entry_token_ensure(
+ /* root= */ NULL,
+ "/etc/kernel",
+ machine_id,
+ /* machine_id_is_random = */ false,
+ &arg_entry_token_type,
+ &arg_entry_token);
+ if (r < 0)
+ return r;
+
+ fn = strjoin("pcrlock.", arg_entry_token, ".cred");
+ if (!fn)
+ return log_oom();
+
+ if (!filename_is_valid(fn))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential name '%s' would not be a valid file name, refusing.", fn);
+
+ joined = path_join(path, "loader/credentials", fn);
+ if (!joined)
+ return log_oom();
+
+ *ret = TAKE_PTR(joined);
+ return 1; /* found! */
+}
+
+static int write_boot_policy_file(const char *json_text) {
+ _cleanup_free_ char *boot_policy_file = NULL;
+ int r;
+
+ assert(json_text);
+
+ r = determine_boot_policy_file(&boot_policy_file);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ log_info("Did not find XBOOTLDR/ESP partition, not writing boot policy file.");
+ return 0;
+ }
+
+ _cleanup_free_ char *c = NULL;
+ r = path_extract_filename(boot_policy_file, &c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to extract file name from %s: %m", boot_policy_file);
+
+ ascii_strlower(c); /* lowercase this file, no matter what, since stored on VFAT, and we don't want to
+ * run into case change incompatibilities */
+
+ _cleanup_(iovec_done) struct iovec encoded = {};
+ r = encrypt_credential_and_warn(
+ CRED_AES256_GCM_BY_NULL,
+ c,
+ now(CLOCK_REALTIME),
+ /* not_after= */ USEC_INFINITY,
+ /* tpm2_device= */ NULL,
+ /* tpm2_hash_pcr_mask= */ 0,
+ /* tpm2_pubkey_path= */ NULL,
+ /* tpm2_pubkey_path_mask= */ 0,
+ &IOVEC_MAKE_STRING(json_text),
+ CREDENTIAL_ALLOW_NULL,
+ &encoded);
+ if (r < 0)
+ return log_error_errno(r, "Failed to encode policy as credential: %m");
+
+ _cleanup_free_ char *base64_buf = NULL;
+ ssize_t base64_size;
+ base64_size = base64mem_full(encoded.iov_base, encoded.iov_len, 79, &base64_buf);
+ if (base64_size < 0)
+ return base64_size;
+
+ r = write_string_file(
+ boot_policy_file,
+ base64_buf,
+ WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_MKDIR_0755);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write boot policy file to '%s': %m", boot_policy_file);
+
+ log_info("Written new boot policy to '%s'.", boot_policy_file);
+ return 1;
+}
+
static int verb_make_policy(int argc, char *argv[], void *userdata) {
int r;
@@ -4562,6 +4689,8 @@ static int verb_make_policy(int argc, char *argv[], void *userdata) {
log_info("Written new policy to '%s' and digest to TPM2 NV index 0x%x.", path, nv_index);
+ (void) write_boot_policy_file(text);
+
log_info("Overall time spent: %s", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start_usec), 1));
return 0;
@@ -4621,7 +4750,7 @@ static int undefine_policy_nv_index(
}
static int verb_remove_policy(int argc, char *argv[], void *userdata) {
- int r;
+ int ret = 0, r;
_cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {};
r = tpm2_pcrlock_policy_load(arg_policy_path, &policy);
@@ -4636,22 +4765,27 @@ static int verb_remove_policy(int argc, char *argv[], void *userdata) {
r = undefine_policy_nv_index(policy.nv_index, &policy.nv_handle, &policy.srk_handle);
if (r < 0)
log_notice("Failed to remove NV index, assuming data out of date, removing policy file.");
- }
-
- if (arg_policy_path) {
- r = remove_policy_file(arg_policy_path);
- if (r < 0)
- return r;
- return 0;
- } else {
- int ret = 0;
+ RET_GATHER(ret, r);
+ }
+ if (arg_policy_path)
+ RET_GATHER(ret, remove_policy_file(arg_policy_path));
+ else {
RET_GATHER(ret, remove_policy_file("/var/lib/systemd/pcrlock.json"));
RET_GATHER(ret, remove_policy_file("/run/systemd/pcrlock.json"));
-
- return ret;
}
+
+ _cleanup_free_ char *boot_policy_file = NULL;
+ r = determine_boot_policy_file(&boot_policy_file);
+ if (r == 0)
+ log_info("Did not find XBOOTLDR/ESP partition, not removing boot policy file.");
+ else if (r > 0) {
+ RET_GATHER(ret, remove_policy_file(boot_policy_file));
+ } else
+ RET_GATHER(ret, r);
+
+ return ret;
}
static int help(int argc, char *argv[], void *userdata) {
@@ -4711,6 +4845,8 @@ static int help(int argc, char *argv[], void *userdata) {
" --pcrlock=PATH .pcrlock file to write expected PCR measurement to\n"
" --policy=PATH JSON file to write policy output to\n"
" --force Write policy even if it matches existing policy\n"
+ " --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
+ " Boot entry token to use for this installation\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@@ -4736,6 +4872,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PCRLOCK,
ARG_POLICY,
ARG_FORCE,
+ ARG_ENTRY_TOKEN,
};
static const struct option options[] = {
@@ -4752,6 +4889,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "pcrlock", required_argument, NULL, ARG_PCRLOCK },
{ "policy", required_argument, NULL, ARG_POLICY },
{ "force", no_argument, NULL, ARG_FORCE },
+ { "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
{}
};
@@ -4899,6 +5037,12 @@ static int parse_argv(int argc, char *argv[]) {
arg_force = true;
break;
+ case ARG_ENTRY_TOKEN:
+ r = parse_boot_entry_token_type(optarg, &arg_entry_token_type, &arg_entry_token);
+ if (r < 0)
+ return r;
+ break;
+
case '?':
return -EINVAL;