diff --git a/man/systemd-measure.xml b/man/systemd-measure.xml
index 66d19a0072..65cb2e503e 100644
--- a/man/systemd-measure.xml
+++ b/man/systemd-measure.xml
@@ -91,6 +91,14 @@
optional. Each option may be used at most once.
+
+
+ When used with the calculate verb, takes the PCR 11 values
+ currently in effect for the system (which should typically reflect the hashes of the currently booted
+ kernel). This can be used in place of and the other switches listed
+ above.
+
+
diff --git a/src/boot/measure.c b/src/boot/measure.c
index bc1f3c8273..a63119fd0b 100644
--- a/src/boot/measure.c
+++ b/src/boot/measure.c
@@ -26,6 +26,7 @@ static char *arg_sections[_UNIFIED_SECTION_MAX] = {};
static char **arg_banks = NULL;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
+static bool arg_current = false;
STATIC_DESTRUCTOR_REGISTER(arg_banks, strv_freep);
@@ -59,6 +60,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --initrd=PATH Path to initrd image\n"
" --splash=PATH Path to splash bitmap\n"
" --dtb=PATH Path to Devicetree file\n"
+ " -c --current Use current PCR values\n"
" --bank=DIGEST Select TPM bank (SHA1, SHA256)\n"
" --json=MODE Output as JSON\n"
" -j Same as --json=pretty on tty, --json=short otherwise\n"
@@ -99,6 +101,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "initrd", required_argument, NULL, ARG_INITRD },
{ "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB },
+ { "current", no_argument, NULL, 'c' },
{ "bank", required_argument, NULL, ARG_BANK },
{ "json", required_argument, NULL, ARG_JSON },
{}
@@ -112,7 +115,7 @@ static int parse_argv(int argc, char *argv[]) {
/* Make sure the arguments list and the section list, stays in sync */
assert_cc(_ARG_SECTION_FIRST + _UNIFIED_SECTION_MAX == _ARG_SECTION_LAST + 1);
- while ((c = getopt_long(argc, argv, "hj", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hjc", options, NULL)) >= 0)
switch (c) {
case 'h':
@@ -135,6 +138,10 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
+ case 'c':
+ arg_current = true;
+ break;
+
case ARG_BANK: {
const EVP_MD *implementation;
@@ -176,6 +183,11 @@ static int parse_argv(int argc, char *argv[]) {
strv_sort(arg_banks);
strv_uniq(arg_banks);
+ if (arg_current)
+ for (UnifiedSection us = 0; us < _UNIFIED_SECTION_MAX; us++)
+ if (arg_sections[us])
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "The --current switch cannot be used in combination with --linux= and related switches.");
+
return 1;
}
@@ -259,6 +271,27 @@ static int measure_pcr(PcrState *pcr_states, size_t n) {
if (!buffer)
return log_oom();
+ if (arg_current) {
+ /* Shortcut things, if we should just use the current PCR value */
+
+ for (size_t i = 0; i < n; i++) {
+ _cleanup_free_ char *p = NULL, *s = NULL;
+
+ if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/%" PRIu32, pcr_states[i].bank, TPM_PCR_INDEX_KERNEL_IMAGE) < 0)
+ return log_oom();
+
+ r = read_virtual_file(p, 4096, &s, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read '%s': %m", p);
+
+ r = unhexmem(strstrip(s), SIZE_MAX, &pcr_states[i].value, &pcr_states[i].value_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode PCR value '%s': %m", s);
+ }
+
+ return 0;
+ }
+
for (UnifiedSection c = 0; c < _UNIFIED_SECTION_MAX; c++) {
_cleanup_(evp_md_ctx_free_all) EVP_MD_CTX **mdctx = NULL;
_cleanup_close_ int fd = -1;
@@ -345,8 +378,8 @@ static int verb_calculate(int argc, char *argv[], void *userdata) {
size_t n = 0;
int r;
- if (!arg_sections[UNIFIED_SECTION_LINUX])
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--linux= switch must be specified, refusing.");
+ if (!arg_sections[UNIFIED_SECTION_LINUX] && !arg_current)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Either --linux= or --current must be specified, refusing.");
pcr_states = new0(PcrState, strv_length(arg_banks) + 1);
if (!pcr_states)