measure: add --current switch for "systemd-measure calculate"

This allows allows shortcutting measurements of the specified files and
use the information from /sys/ instead.

This is not too useful on its own given that "systemd-measure status"
already exists which displays the current, relevant PCR values. The main
difference is how "complete" the information is. "status" will detect if
the measurements make any sense, and show more than PCR 11. "calculate
--current" otoh only reads PCR 11 and uses that, and that's really it.

This is mainly preparation for later work to add PCR signing to the
tool, where usually it makes most sense to sign prepared kernel images,
but for testing it's really useful to shortcut signing to the current
PCR values instead
This commit is contained in:
Lennart Poettering 2022-08-17 18:40:19 +02:00 committed by Luca Boccassi
parent 8e7e4a730b
commit 127b72da2b
2 changed files with 44 additions and 3 deletions

View file

@ -91,6 +91,14 @@
optional. Each option may be used at most once.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--current</option></term>
<listitem><para>When used with the <command>calculate</command> 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 <option>--linux=</option> and the other switches listed
above.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--bank=DIGEST</option></term>

View file

@ -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)