diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-12-06 21:15:06 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2023-04-05 20:51:31 +0200 |
commit | a62e12dad12434aeecccd58e78bcae4cf1b0d730 (patch) | |
tree | 314f3438ce643d71e75c7a8b88a50e90a3c38852 | |
parent | 97ce55e3e59f0361af4da6b09cce7e239927f812 (diff) | |
download | systemd-a62e12dad12434aeecccd58e78bcae4cf1b0d730.tar.gz |
analyze: add 'image-policy' tool for analyzing image dissection policies
-rw-r--r-- | src/analyze/analyze-image-policy.c | 152 | ||||
-rw-r--r-- | src/analyze/analyze-image-policy.h | 3 | ||||
-rw-r--r-- | src/analyze/analyze.c | 2 | ||||
-rw-r--r-- | src/analyze/meson.build | 1 | ||||
-rwxr-xr-x | test/units/testsuite-65.sh | 12 |
5 files changed, 170 insertions, 0 deletions
diff --git a/src/analyze/analyze-image-policy.c b/src/analyze/analyze-image-policy.c new file mode 100644 index 0000000000..e670fe5c4d --- /dev/null +++ b/src/analyze/analyze-image-policy.c @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "analyze-image-policy.h" +#include "analyze.h" +#include "format-table.h" +#include "terminal-util.h" + +static int table_add_designator_line(Table *table, PartitionDesignator d, PartitionPolicyFlags f) { + _cleanup_free_ char *q = NULL; + const char *color; + int r; + + assert(table); + assert(f >= 0); + + if (partition_policy_flags_to_string(f & _PARTITION_POLICY_USE_MASK, /* simplify= */ true, &q) < 0) + return log_oom(); + + color = (f & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_IGNORE ? ansi_grey() : + ((f & (PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT)) == + (PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ABSENT)) ? ansi_highlight_yellow() : + (f & _PARTITION_POLICY_USE_MASK) == PARTITION_POLICY_ABSENT ? ansi_highlight_red() : + !(f & PARTITION_POLICY_UNPROTECTED) ? ansi_highlight_green() : NULL; + + if (d < 0) + r = table_add_many(table, + TABLE_STRING, "default", + TABLE_SET_COLOR, ansi_highlight_green(), + TABLE_STRING, q, + TABLE_SET_COLOR, color); + else + r = table_add_many(table, + TABLE_STRING, partition_designator_to_string(d), + TABLE_SET_COLOR, ansi_normal(), + TABLE_STRING, q, + TABLE_SET_COLOR, color); + if (r < 0) + return table_log_add_error(r); + + switch (f & _PARTITION_POLICY_READ_ONLY_MASK) { + + case PARTITION_POLICY_READ_ONLY_ON: + r = table_add_many(table, TABLE_BOOLEAN, true); + break; + + case PARTITION_POLICY_READ_ONLY_OFF: + r = table_add_many(table, TABLE_BOOLEAN, false); + break; + + default: + r = table_add_many(table, TABLE_EMPTY); + break; + } + if (r < 0) + return table_log_add_error(r); + + switch (f & _PARTITION_POLICY_GROWFS_MASK) { + + case PARTITION_POLICY_GROWFS_ON: + r = table_add_many(table, TABLE_BOOLEAN, true); + break; + + case PARTITION_POLICY_GROWFS_OFF: + r = table_add_many(table, TABLE_BOOLEAN, false); + break; + + default: + r = table_add_many(table, TABLE_EMPTY); + break; + } + + if (r < 0) + return table_log_add_error(r); + + return 0; +} + +int verb_image_policy(int argc, char *argv[], void *userdata) { + int r; + + for (int i = 1; i < argc; i++) { + _cleanup_(table_unrefp) Table *table = NULL; + _cleanup_(image_policy_freep) ImagePolicy *pbuf = NULL; + _cleanup_free_ char *as_string = NULL, *as_string_simplified = NULL; + const ImagePolicy *p; + + /* NB: The magic '@' strings are not officially documented for now, since we might change + * around defaults (and in particular where precisely to reuse policy). We should document + * them once the dust has settled a bit. For now it's just useful for debugging and + * introspect our own defaults without guaranteeing API safety. */ + if (streq(argv[i], "@sysext")) + p = &image_policy_sysext; + else if (streq(argv[i], "@container")) + p = &image_policy_container; + else if (streq(argv[i], "@service")) + p = &image_policy_service; + else if (streq(argv[i], "@host")) + p = &image_policy_host; + else { + r = image_policy_from_string(argv[i], &pbuf); + if (r < 0) + return log_error_errno(r, "Failed to parse image policy '%s': %m", argv[i]); + + p = pbuf; + } + + r = image_policy_to_string(p, /* simplify= */ false, &as_string); + if (r < 0) + return log_error_errno(r, "Failed to format policy '%s' as string: %m", argv[i]); + + r = image_policy_to_string(p, /* simplify= */ true, &as_string_simplified); + if (r < 0) + return log_error_errno(r, "Failed to format policy '%s' as string: %m", argv[i]); + + pager_open(arg_pager_flags); + + if (streq(as_string, as_string_simplified)) + printf("Analyzing policy: %s%s%s\n", ansi_highlight_magenta_underline(), as_string, ansi_normal()); + else + printf("Analyzing policy: %s%s%s\n" + " Long form: %s%s%s\n", + ansi_highlight(), as_string_simplified, ansi_normal(), + ansi_grey(), as_string, ansi_normal()); + + table = table_new("partition", "mode", "read-only", "growfs"); + if (!table) + return log_oom(); + + (void) table_set_ersatz_string(table, TABLE_ERSATZ_DASH); + + for (PartitionDesignator d = 0; d < _PARTITION_DESIGNATOR_MAX; d++) { + PartitionPolicyFlags f = image_policy_get_exhaustively(p, d); + assert(f >= 0); + + r = table_add_designator_line(table, d, f); + if (r < 0) + return r; + } + + r = table_add_designator_line(table, _PARTITION_DESIGNATOR_INVALID, image_policy_default(p)); + if (r < 0) + return r; + + putc('\n', stdout); + + r = table_print(table, NULL); + if (r < 0) + return r; + } + + return EXIT_SUCCESS; +} diff --git a/src/analyze/analyze-image-policy.h b/src/analyze/analyze-image-policy.h new file mode 100644 index 0000000000..fa08447822 --- /dev/null +++ b/src/analyze/analyze-image-policy.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +int verb_image_policy(int argc, char *argv[], void *userdata); diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 8bc533b20d..ddc71b98b0 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -39,6 +39,7 @@ #include "analyze-unit-files.h" #include "analyze-unit-paths.h" #include "analyze-verify.h" +#include "analyze-image-policy.h" #include "build.h" #include "bus-error.h" #include "bus-locator.h" @@ -640,6 +641,7 @@ static int run(int argc, char *argv[]) { { "inspect-elf", 2, VERB_ANY, 0, verb_elf_inspection }, { "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc }, { "fdstore", 2, VERB_ANY, 0, verb_fdstore }, + { "image-policy", 2, 2, 0, verb_image_policy }, {} }; diff --git a/src/analyze/meson.build b/src/analyze/meson.build index 695089a0be..c50c35f09f 100644 --- a/src/analyze/meson.build +++ b/src/analyze/meson.build @@ -13,6 +13,7 @@ systemd_analyze_sources = files( 'analyze-exit-status.c', 'analyze-fdstore.c', 'analyze-filesystems.c', + 'analyze-image-policy.c', 'analyze-inspect-elf.c', 'analyze-log-control.c', 'analyze-malloc.c', diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh index edaf667107..f28edf275e 100755 --- a/test/units/testsuite-65.sh +++ b/test/units/testsuite-65.sh @@ -816,6 +816,18 @@ name=$(echo "$output" | awk '{ print $4 }') check deny yes /run/systemd/transient/"$name" check deny no "$name" +# Let's also test the "image-policy" verb + +systemd-analyze image-policy '*' 2>&1 | grep -q -F "Long form: =verity+signed+encrypted+unprotected+unused+absent" +systemd-analyze image-policy '-' 2>&1 | grep -q -F "Long form: =unused+absent" +systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -q -F "Long form: usr=verity:home=encrypted:=unused+absent" +systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -q -e '^home \+encrypted \+' +systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -q -e '^usr \+verity \+' +systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -q -e '^root \+ignore \+' +systemd-analyze image-policy 'home=encrypted:usr=verity' 2>&1 | grep -q -e '^usr-verity \+unprotected \+' + +(! systemd-analyze image-policy 'doedel' ) + systemd-analyze log-level info echo OK >/testok |