analyze: add new "pcrs" verb
It shows the PCRs we know about along with their name strings and current values.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
int verb_pcrs(int argc, char *argv[], void *userdata);
|
||||
@@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user