From: Lennart Poettering Date: Tue, 27 Jun 2023 16:45:34 +0000 (+0200) Subject: analyze: add new "pcrs" verb X-Git-Tag: v254-rc1~92 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f70c90f5ca2226cf578cf9da18b7aa8f611347d2;p=thirdparty%2Fsystemd.git analyze: add new "pcrs" verb It shows the PCRs we know about along with their name strings and current values. --- diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 4aa73d91f74..145d3f61880 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -168,6 +168,12 @@ image-policy POLICY + + systemd-analyze + OPTIONS + pcrs + PCR + @@ -883,6 +889,43 @@ var ignore - - default ignore - - + + + <command>systemd-analyze pcrs <optional><replaceable>PCR</replaceable>…</optional></command> + + This command shows the known TPM2 PCRs along with their identifying names and current values. + + + Example Output + + $ systemd-analyze pcrs +NR NAME SHA256 + 0 platform-code bcd2eb527108bbb1f5528409bcbe310aa9b74f687854cc5857605993f3d9eb11 + 1 platform-config b60622856eb7ce52637b80f30a520e6e87c347daa679f3335f4f1a600681bb01 + 2 external-code 1471262403e9a62f9c392941300b4807fbdb6f0bfdd50abfab752732087017dd + 3 external-config 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969 + 4 boot-loader-code 939f7fa1458e1f7ce968874d908e524fc0debf890383d355e4ce347b7b78a95c + 5 boot-loader-config 864c61c5ea5ecbdb6951e6cb6d9c1f4b4eac79772f7fe13b8bece569d83d3768 + 6 - 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969 + 7 secure-boot-policy 9c905bd9b9891bfb889b90a54c4b537b889cfa817c4389cc25754823a9443255 + 8 - 0000000000000000000000000000000000000000000000000000000000000000 + 9 kernel-initrd 9caa29b128113ef42aa53d421f03437be57211e5ebafc0fa8b5d4514ee37ff0c +10 ima 5ea9e3dab53eb6b483b6ec9e3b2c712bea66bca1b155637841216e0094387400 +11 kernel-boot 0000000000000000000000000000000000000000000000000000000000000000 +12 kernel-config 627ffa4b405e911902fe1f1a8b0164693b31acab04f805f15bccfe2209c7eace +13 sysexts 0000000000000000000000000000000000000000000000000000000000000000 +14 shim-policy 0000000000000000000000000000000000000000000000000000000000000000 +15 system-identity 0000000000000000000000000000000000000000000000000000000000000000 +16 debug 0000000000000000000000000000000000000000000000000000000000000000 +17 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +18 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +19 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +20 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +21 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +22 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +23 application-support 0000000000000000000000000000000000000000000000000000000000000000 + + diff --git a/src/analyze/analyze-pcrs.c b/src/analyze/analyze-pcrs.c new file mode 100644 index 00000000000..b9a6ac144aa --- /dev/null +++ b/src/analyze/analyze-pcrs.c @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "analyze.h" +#include "analyze-pcrs.h" +#include "fileio.h" +#include "format-table.h" +#include "hexdecoct.h" +#include "terminal-util.h" +#include "tpm2-util.h" + +static int get_pcr_alg(const char **ret) { + assert(ret); + + FOREACH_STRING(alg, "sha256", "sha1") { + _cleanup_free_ char *p = NULL; + + if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/0", alg) < 0) + return log_oom(); + + if (access(p, F_OK) < 0) { + if (errno != -ENOENT) + return log_error_errno(errno, "Failed to determine whether %s exists: %m", p); + } else { + *ret = alg; + return 1; + } + } + + log_notice("Kernel does not support reading PCR values."); + *ret = NULL; + return 0; +} + +static int get_current_pcr(const char *alg, uint32_t pcr, void **ret, size_t *ret_size) { + _cleanup_free_ char *p = NULL, *s = NULL; + _cleanup_free_ void *buf = NULL; + size_t ss = 0, bufsize = 0; + int r; + + assert(alg); + assert(ret); + assert(ret_size); + + if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/%" PRIu32, alg, pcr) < 0) + return log_oom(); + + r = read_virtual_file(p, 4096, &s, &ss); + if (r < 0) + return log_error_errno(r, "Failed to read '%s': %m", p); + + r = unhexmem(s, ss, &buf, &bufsize); + if (r < 0) + return log_error_errno(r, "Failed to decode hex PCR data '%s': %m", s); + + *ret = TAKE_PTR(buf); + *ret_size = bufsize; + return 0; +} + +static int add_pcr_to_table(Table *table, const char *alg, uint32_t pcr) { + _cleanup_free_ char *h = NULL; + const char *color = NULL; + int r; + + if (alg) { + _cleanup_free_ void *buf = NULL; + size_t bufsize = 0; + + r = get_current_pcr(alg, pcr, &buf, &bufsize); + if (r < 0) + return r; + + h = hexmem(buf, bufsize); + if (!h) + return log_oom(); + + /* Grey out PCRs that are not sensibly initialized */ + if (memeqbyte(0, buf, bufsize) || + memeqbyte(0xFFU, buf, bufsize)) + color = ANSI_GREY; + } + + r = table_add_many(table, + TABLE_UINT32, pcr, + TABLE_STRING, pcr_index_to_string(pcr), + TABLE_STRING, h, + TABLE_SET_COLOR, color); + if (r < 0) + return table_log_add_error(r); + + return 0; +} + +int verb_pcrs(int argc, char *argv[], void *userdata) { + _cleanup_(table_unrefp) Table *table = NULL; + const char *alg = NULL; + int r; + + if (tpm2_support() != TPM2_SUPPORT_FULL) + log_notice("System has not TPM2 support, not showing PCR state."); + else { + r = get_pcr_alg(&alg); + if (r < 0) + return r; + } + + table = table_new("nr", "name", alg); + if (!table) + return log_oom(); + + (void) table_set_align_percent(table, table_get_cell(table, 0, 0), 100); + (void) table_set_ersatz_string(table, TABLE_ERSATZ_DASH); + + if (!alg) /* hide hash column if we couldn't acquire it */ + (void) table_set_display(table, 0, 1); + + if (strv_isempty(strv_skip(argv, 1))) + for (uint32_t pi = 0; pi < _PCR_INDEX_MAX_DEFINED; pi++) { + r = add_pcr_to_table(table, alg, pi); + if (r < 0) + return r; + } + else { + for (int i = 1; i < argc; i++) { + int pi; + + pi = pcr_index_from_string(argv[i]); + if (pi < 0) + return log_error_errno(pi, "PCR index \"%s\" not known.", argv[i]); + + r = add_pcr_to_table(table, alg, pi); + if (r < 0) + return r; + } + + (void) table_set_sort(table, (size_t) 0); + } + + r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, /* show_header= */true); + if (r < 0) + return log_error_errno(r, "Failed to output table: %m"); + + return EXIT_SUCCESS; +} diff --git a/src/analyze/analyze-pcrs.h b/src/analyze/analyze-pcrs.h new file mode 100644 index 00000000000..2a59511885a --- /dev/null +++ b/src/analyze/analyze-pcrs.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +int verb_pcrs(int argc, char *argv[], void *userdata); diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index b555c713fc3..eb5fceba8de 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -28,6 +28,7 @@ #include "analyze-inspect-elf.h" #include "analyze-log-control.h" #include "analyze-malloc.h" +#include "analyze-pcrs.h" #include "analyze-plot.h" #include "analyze-security.h" #include "analyze-service-watchdogs.h" @@ -234,6 +235,7 @@ static int help(int argc, char *argv[], void *userdata) { " inspect-elf FILE... Parse and print ELF package metadata\n" " malloc [D-BUS SERVICE...] Dump malloc stats of a D-Bus service\n" " fdstore SERVICE... Show file descriptor store contents of service\n" + " pcrs [PCR...] Show TPM2 PCRs and their names\n" "\nOptions:\n" " --recursive-errors=MODE Control which units are verified\n" " --offline=BOOL Perform a security review on unit file(s)\n" @@ -545,9 +547,9 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --offline= is only supported for security right now."); - if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf", "plot", "fdstore")) + if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf", "plot", "fdstore", "pcrs")) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Option --json= is only supported for security, inspect-elf, plot, and fdstore right now."); + "Option --json= is only supported for security, inspect-elf, plot, fdstore, pcrs right now."); if (arg_threshold != 100 && !streq_ptr(argv[optind], "security")) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -636,6 +638,7 @@ static int run(int argc, char *argv[]) { { "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc }, { "fdstore", 2, VERB_ANY, 0, verb_fdstore }, { "image-policy", 2, 2, 0, verb_image_policy }, + { "pcrs", VERB_ANY, VERB_ANY, 0, verb_pcrs }, {} }; diff --git a/src/analyze/meson.build b/src/analyze/meson.build index c50c35f09f6..911c0bc3ed2 100644 --- a/src/analyze/meson.build +++ b/src/analyze/meson.build @@ -17,6 +17,7 @@ systemd_analyze_sources = files( 'analyze-inspect-elf.c', 'analyze-log-control.c', 'analyze-malloc.c', + 'analyze-pcrs.c', 'analyze-plot.c', 'analyze-security.c', 'analyze-service-watchdogs.c', diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 01a7a27ff39..bbff2a934b1 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -4046,3 +4046,4 @@ static const char* const pcr_index_table[_PCR_INDEX_MAX_DEFINED] = { }; DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_FALLBACK(pcr_index, int, TPM2_PCRS_MAX - 1); +DEFINE_STRING_TABLE_LOOKUP_TO_STRING(pcr_index, int); diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 953e936c75f..ea17b26b309 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -221,4 +221,5 @@ int tpm2_util_pbkdf2_hmac_sha256(const void *pass, size_t saltlen, uint8_t res[static SHA256_DIGEST_SIZE]); -int pcr_index_from_string(const char *s); +int pcr_index_from_string(const char *s) _pure_; +const char *pcr_index_to_string(int pcr) _const_; diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh index c6a81b4b4eb..4c8c4146edb 100755 --- a/test/units/testsuite-65.sh +++ b/test/units/testsuite-65.sh @@ -838,6 +838,11 @@ systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -q -e '^usr (! systemd-analyze image-policy 'doedel') +# Output is very hard to predict, but let's run it for coverage anyway +systemd-analyze pcrs +systemd-analyze pcrs --json=pretty +systemd-analyze pcrs 14 7 0 ima + systemd-analyze log-level info echo OK >/testok