mirror of
https://github.com/systemd/systemd.git
synced 2025-09-12 01:44:46 +03:00
measure: add json output
This commit is contained in:
@@ -101,6 +101,8 @@
|
|||||||
<literal>sha512</literal>.</para></listitem>
|
<literal>sha512</literal>.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<xi:include href="standard-options.xml" xpointer="json" />
|
||||||
|
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||||
<xi:include href="standard-options.xml" xpointer="help" />
|
<xi:include href="standard-options.xml" xpointer="help" />
|
||||||
<xi:include href="standard-options.xml" xpointer="version" />
|
<xi:include href="standard-options.xml" xpointer="version" />
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
|
#include "json.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "openssl-util.h"
|
#include "openssl-util.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
@@ -23,6 +24,8 @@
|
|||||||
|
|
||||||
static char *arg_sections[_UNIFIED_SECTION_MAX] = {};
|
static char *arg_sections[_UNIFIED_SECTION_MAX] = {};
|
||||||
static char **arg_banks = NULL;
|
static char **arg_banks = NULL;
|
||||||
|
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||||
|
static PagerFlags arg_pager_flags = 0;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_banks, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_banks, strv_freep);
|
||||||
|
|
||||||
@@ -47,15 +50,18 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||||||
" status Show current PCR values\n"
|
" status Show current PCR values\n"
|
||||||
" calculate Calculate expected PCR values\n"
|
" calculate Calculate expected PCR values\n"
|
||||||
"\n%3$sOptions:%4$s\n"
|
"\n%3$sOptions:%4$s\n"
|
||||||
" -h --help Show this help\n"
|
" -h --help Show this help\n"
|
||||||
" --version Print version\n"
|
" --version Print version\n"
|
||||||
" --linux=PATH Path Linux kernel ELF image\n"
|
" --no-pager Do not pipe output into a pager\n"
|
||||||
" --osrel=PATH Path to os-release file\n"
|
" --linux=PATH Path Linux kernel ELF image\n"
|
||||||
" --cmdline=PATH Path to file with kernel command line\n"
|
" --osrel=PATH Path to os-release file\n"
|
||||||
" --initrd=PATH Path to initrd image\n"
|
" --cmdline=PATH Path to file with kernel command line\n"
|
||||||
" --splash=PATH Path to splash bitmap\n"
|
" --initrd=PATH Path to initrd image\n"
|
||||||
" --dtb=PATH Path to Devicetree file\n"
|
" --splash=PATH Path to splash bitmap\n"
|
||||||
" --bank=DIGEST Select TPM bank (SHA1, SHA256)\n"
|
" --dtb=PATH Path to Devicetree file\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"
|
||||||
"\nSee the %2$s for details.\n",
|
"\nSee the %2$s for details.\n",
|
||||||
program_invocation_short_name,
|
program_invocation_short_name,
|
||||||
link,
|
link,
|
||||||
@@ -70,6 +76,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||||||
static int parse_argv(int argc, char *argv[]) {
|
static int parse_argv(int argc, char *argv[]) {
|
||||||
enum {
|
enum {
|
||||||
ARG_VERSION = 0x100,
|
ARG_VERSION = 0x100,
|
||||||
|
ARG_NO_PAGER,
|
||||||
_ARG_SECTION_FIRST,
|
_ARG_SECTION_FIRST,
|
||||||
ARG_LINUX = _ARG_SECTION_FIRST,
|
ARG_LINUX = _ARG_SECTION_FIRST,
|
||||||
ARG_OSREL,
|
ARG_OSREL,
|
||||||
@@ -79,18 +86,21 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
_ARG_SECTION_LAST,
|
_ARG_SECTION_LAST,
|
||||||
ARG_DTB = _ARG_SECTION_LAST,
|
ARG_DTB = _ARG_SECTION_LAST,
|
||||||
ARG_BANK,
|
ARG_BANK,
|
||||||
|
ARG_JSON,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, ARG_VERSION },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
{ "linux", required_argument, NULL, ARG_LINUX },
|
{ "version", no_argument, NULL, ARG_VERSION },
|
||||||
{ "osrel", required_argument, NULL, ARG_OSREL },
|
{ "linux", required_argument, NULL, ARG_LINUX },
|
||||||
{ "cmdline", required_argument, NULL, ARG_CMDLINE },
|
{ "osrel", required_argument, NULL, ARG_OSREL },
|
||||||
{ "initrd", required_argument, NULL, ARG_INITRD },
|
{ "cmdline", required_argument, NULL, ARG_CMDLINE },
|
||||||
{ "splash", required_argument, NULL, ARG_SPLASH },
|
{ "initrd", required_argument, NULL, ARG_INITRD },
|
||||||
{ "dtb", required_argument, NULL, ARG_DTB },
|
{ "splash", required_argument, NULL, ARG_SPLASH },
|
||||||
{ "bank", required_argument, NULL, ARG_BANK },
|
{ "dtb", required_argument, NULL, ARG_DTB },
|
||||||
|
{ "bank", required_argument, NULL, ARG_BANK },
|
||||||
|
{ "json", required_argument, NULL, ARG_JSON },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -102,7 +112,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
/* Make sure the arguments list and the section list, stays in sync */
|
/* Make sure the arguments list and the section list, stays in sync */
|
||||||
assert_cc(_ARG_SECTION_FIRST + _UNIFIED_SECTION_MAX == _ARG_SECTION_LAST + 1);
|
assert_cc(_ARG_SECTION_FIRST + _UNIFIED_SECTION_MAX == _ARG_SECTION_LAST + 1);
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "hj", options, NULL)) >= 0)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
@@ -112,6 +122,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
case ARG_VERSION:
|
case ARG_VERSION:
|
||||||
return version();
|
return version();
|
||||||
|
|
||||||
|
case ARG_NO_PAGER:
|
||||||
|
arg_pager_flags |= PAGER_DISABLE;
|
||||||
|
break;
|
||||||
|
|
||||||
case _ARG_SECTION_FIRST..._ARG_SECTION_LAST: {
|
case _ARG_SECTION_FIRST..._ARG_SECTION_LAST: {
|
||||||
UnifiedSection section = c - _ARG_SECTION_FIRST;
|
UnifiedSection section = c - _ARG_SECTION_FIRST;
|
||||||
|
|
||||||
@@ -134,6 +148,17 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'j':
|
||||||
|
arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_JSON:
|
||||||
|
r = parse_json_argument(optarg, &arg_json_format_flags);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@@ -313,6 +338,7 @@ static int measure_pcr(PcrState *pcr_states, size_t n) {
|
|||||||
|
|
||||||
static int verb_calculate(int argc, char *argv[], void *userdata) {
|
static int verb_calculate(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
|
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -351,17 +377,49 @@ static int verb_calculate(int argc, char *argv[], void *userdata) {
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
_cleanup_free_ char *hd = NULL, *b = NULL;
|
_cleanup_free_ char *b = NULL;
|
||||||
|
|
||||||
hd = hexmem(pcr_states[i].value, pcr_states[i].value_size);
|
|
||||||
if (!hd)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
b = strdup(EVP_MD_name(pcr_states[i].md));
|
b = strdup(EVP_MD_name(pcr_states[i].md));
|
||||||
if (!b)
|
if (!b)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
printf("%" PRIu32 ":%s=%s\n", TPM_PCR_INDEX_KERNEL_IMAGE, ascii_strlower(b), hd);
|
ascii_strlower(b);
|
||||||
|
|
||||||
|
if (arg_json_format_flags & JSON_FORMAT_OFF) {
|
||||||
|
_cleanup_free_ char *hd = NULL;
|
||||||
|
|
||||||
|
hd = hexmem(pcr_states[i].value, pcr_states[i].value_size);
|
||||||
|
if (!hd)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
printf("%" PRIu32 ":%s=%s\n", TPM_PCR_INDEX_KERNEL_IMAGE, b, hd);
|
||||||
|
} else {
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *bv = NULL;
|
||||||
|
|
||||||
|
r = json_build(&bv,
|
||||||
|
JSON_BUILD_ARRAY(
|
||||||
|
JSON_BUILD_OBJECT(
|
||||||
|
JSON_BUILD_PAIR("pcr", JSON_BUILD_INTEGER(TPM_PCR_INDEX_KERNEL_IMAGE)),
|
||||||
|
JSON_BUILD_PAIR("hash", JSON_BUILD_HEX(pcr_states[i].value, pcr_states[i].value_size))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to build JSON object: %m");
|
||||||
|
|
||||||
|
r = json_variant_set_field(&w, b, bv);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to add bank info to object: %m");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
|
||||||
|
|
||||||
|
if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
|
||||||
|
pager_open(arg_pager_flags);
|
||||||
|
|
||||||
|
json_variant_dump(w, arg_json_format_flags, stdout, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -441,6 +499,7 @@ static int validate_stub(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int verb_status(int argc, char *argv[], void *userdata) {
|
static int verb_status(int argc, char *argv[], void *userdata) {
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
uint32_t nr;
|
uint32_t nr;
|
||||||
@@ -460,7 +519,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
|||||||
for (size_t i = 0; i < ELEMENTSOF(relevant_pcrs); i++) {
|
for (size_t i = 0; i < ELEMENTSOF(relevant_pcrs); i++) {
|
||||||
|
|
||||||
STRV_FOREACH(bank, arg_banks) {
|
STRV_FOREACH(bank, arg_banks) {
|
||||||
_cleanup_free_ char *b = NULL, *p = NULL, *s = NULL, *f = NULL;
|
_cleanup_free_ char *b = NULL, *p = NULL, *s = NULL;
|
||||||
_cleanup_free_ void *h = NULL;
|
_cleanup_free_ void *h = NULL;
|
||||||
size_t l;
|
size_t l;
|
||||||
|
|
||||||
@@ -481,27 +540,60 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to decode PCR value '%s': %m", s);
|
return log_error_errno(r, "Failed to decode PCR value '%s': %m", s);
|
||||||
|
|
||||||
f = hexmem(h, l);
|
if (arg_json_format_flags & JSON_FORMAT_OFF) {
|
||||||
if (!h)
|
_cleanup_free_ char *f = NULL;
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
if (bank == arg_banks) {
|
f = hexmem(h, l);
|
||||||
/* before the first line for each PCR, write a short descriptive text to
|
if (!h)
|
||||||
* stderr, and leave the primary content on stdout */
|
return log_oom();
|
||||||
fflush(stdout);
|
|
||||||
fprintf(stderr, "%s# PCR[%" PRIu32 "] %s%s%s\n",
|
if (bank == arg_banks) {
|
||||||
ansi_grey(),
|
/* before the first line for each PCR, write a short descriptive text to
|
||||||
relevant_pcrs[i].nr,
|
* stderr, and leave the primary content on stdout */
|
||||||
relevant_pcrs[i].description,
|
fflush(stdout);
|
||||||
memeqzero(h, l) ? " (NOT SET!)" : "",
|
fprintf(stderr, "%s# PCR[%" PRIu32 "] %s%s%s\n",
|
||||||
ansi_normal());
|
ansi_grey(),
|
||||||
fflush(stderr);
|
relevant_pcrs[i].nr,
|
||||||
|
relevant_pcrs[i].description,
|
||||||
|
memeqzero(h, l) ? " (NOT SET!)" : "",
|
||||||
|
ansi_normal());
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%" PRIu32 ":%s=%s\n", relevant_pcrs[i].nr, b, f);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *bv = NULL, *a = NULL;
|
||||||
|
|
||||||
|
r = json_build(&bv,
|
||||||
|
JSON_BUILD_OBJECT(
|
||||||
|
JSON_BUILD_PAIR("pcr", JSON_BUILD_INTEGER(relevant_pcrs[i].nr)),
|
||||||
|
JSON_BUILD_PAIR("hash", JSON_BUILD_HEX(h, l))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to build JSON object: %m");
|
||||||
|
|
||||||
|
a = json_variant_ref(json_variant_by_key(v, b));
|
||||||
|
|
||||||
|
r = json_variant_append_array(&a, bv);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to append PCR entry to JSON array: %m");
|
||||||
|
|
||||||
|
r = json_variant_set_field(&v, b, a);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to add bank info to object: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%" PRIu32 ":%s=%s\n", relevant_pcrs[i].nr, b, f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
|
||||||
|
if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
|
||||||
|
pager_open(arg_pager_flags);
|
||||||
|
|
||||||
|
json_variant_dump(v, arg_json_format_flags, stdout, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user