diff options
author | Frantisek Sumsal <frantisek@sumsal.cz> | 2023-03-26 17:04:57 +0200 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@gmail.com> | 2023-03-27 11:00:30 +0100 |
commit | 4c9c91defcdb7f8f40337a26c0d55b725d4245e1 (patch) | |
tree | d9010a9c194c8be9d84cd136c005127aae741fe4 | |
parent | 830e52caa2bf1a29f56cb93e7ed85acb1bda11c3 (diff) | |
download | systemd-4c9c91defcdb7f8f40337a26c0d55b725d4245e1.tar.gz |
test: verify the journal with and without a sealing key
The bit flips during journal verification cause various types of journal
corruptions, so it's useful to go through it even without a sealing key
to see how we handle corrupted stuff.
Also, provide a sealing key if running in "CI mode" (i.e. arguments),
to check the FSS-related codepaths in CIs as well.
-rw-r--r-- | src/journal/meson.build | 1 | ||||
-rw-r--r-- | src/journal/test-journal-verify.c | 131 |
2 files changed, 96 insertions, 36 deletions
diff --git a/src/journal/meson.build b/src/journal/meson.build index 1490113f1c..c540a1ce45 100644 --- a/src/journal/meson.build +++ b/src/journal/meson.build @@ -105,6 +105,7 @@ tests += [ { 'sources' : files('test-journal-verify.c'), 'base' : test_journal_base, + 'timeout' : 90, }, { 'sources' : files('test-journal.c'), diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index 7a90079fc8..f15071d81d 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -12,6 +12,7 @@ #include "managed-journal-file.h" #include "mmap-cache.h" #include "rm-rf.h" +#include "strv.h" #include "terminal-util.h" #include "tests.h" @@ -45,7 +46,17 @@ static int raw_verify(const char *fn, const char *verification_key) { m = mmap_cache_new(); assert_se(m != NULL); - r = journal_file_open(-1, fn, O_RDONLY, JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0), 0666, UINT64_MAX, NULL, m, NULL, &f); + r = journal_file_open( + /* fd= */ -1, + fn, + O_RDONLY, + JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0), + 0666, + /* compress_threshold_bytes= */ UINT64_MAX, + /* metrics= */ NULL, + m, + /* template= */ NULL, + &f); if (r < 0) return r; @@ -55,16 +66,15 @@ static int raw_verify(const char *fn, const char *verification_key) { return r; } -static int run_test(int argc, char *argv[]) { +static int run_test(const char *verification_key, ssize_t max_iterations) { _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL; char t[] = "/var/tmp/journal-XXXXXX"; - unsigned n; + struct stat st; JournalFile *f; ManagedJournalFile *df; - const char *verification_key = argv[1]; usec_t from = 0, to = 0, total = 0; - struct stat st; - uint64_t p; + uint64_t start, end; + int r; m = mmap_cache_new(); assert_se(m != NULL); @@ -79,32 +89,57 @@ static int run_test(int argc, char *argv[]) { assert_se(chdir(t) >= 0); (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL); - log_info("Generating..."); - - assert_se(managed_journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0), 0666, UINT64_MAX, NULL, m, NULL, NULL, &df) == 0); - - for (n = 0; n < N_ENTRIES; n++) { + log_info("Generating a test journal"); + + assert_se(managed_journal_file_open( + /* fd= */ -1, + "test.journal", + O_RDWR|O_CREAT, + JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0), + 0666, + /* compress_threshold_bytes= */ UINT64_MAX, + /* metrics= */ NULL, + m, + /* deferred_closes= */ NULL, + /* template= */ NULL, + &df) == 0); + + for (size_t n = 0; n < N_ENTRIES; n++) { + _cleanup_free_ char *test = NULL; struct iovec iovec; struct dual_timestamp ts; - char *test; dual_timestamp_get(&ts); - assert_se(asprintf(&test, "RANDOM=%li", random() % RANDOM_RANGE)); - iovec = IOVEC_MAKE_STRING(test); - - assert_se(journal_file_append_entry(df->file, &ts, NULL, &iovec, 1, NULL, NULL, NULL, NULL) == 0); - - free(test); + assert_se(journal_file_append_entry( + df->file, + &ts, + /* boot_id= */ NULL, + &iovec, + /* n_iovec= */ 1, + /* seqnum= */ NULL, + /* seqnum_id= */ NULL, + /* ret_object= */ NULL, + /* ret_offset= */ NULL) == 0); } (void) managed_journal_file_close(df); - log_info("Verifying..."); - - assert_se(journal_file_open(-1, "test.journal", O_RDONLY, JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL: 0), 0666, UINT64_MAX, NULL, m, NULL, &f) == 0); - /* journal_file_print_header(f); */ + log_info("Verifying with key: %s", strna(verification_key)); + + assert_se(journal_file_open( + /* fd= */ -1, + "test.journal", + O_RDONLY, + JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0), + 0666, + /* compress_threshold_bytes= */ UINT64_MAX, + /* metrics= */ NULL, + m, + /* template= */ NULL, + &f) == 0); + journal_file_print_header(f); journal_file_dump(f); assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0); @@ -116,37 +151,61 @@ static int run_test(int argc, char *argv[]) { FORMAT_TIMESPAN(total > to ? total - to : 0, 0)); (void) journal_file_close(f); + assert_se(stat("test.journal", &st) >= 0); - if (verification_key) { - log_info("Toggling bits..."); - - assert_se(stat("test.journal", &st) >= 0); + start = 38448 * 8 + 0; + end = max_iterations < 0 ? (uint64_t)st.st_size * 8 : start + max_iterations; + log_info("Toggling bits %"PRIu64 " to %"PRIu64, start, end); - for (p = 38448*8+0; p < ((uint64_t) st.st_size * 8); p ++) { - bit_toggle("test.journal", p); + for (uint64_t p = start; p < end; p++) { + bit_toggle("test.journal", p); + if (max_iterations < 0) log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8); - if (raw_verify("test.journal", verification_key) >= 0) - log_notice(ANSI_HIGHLIGHT_RED ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_NORMAL, p / 8, p % 8); + r = raw_verify("test.journal", verification_key); + /* Suppress the notice when running in the limited (CI) mode */ + if (verification_key && max_iterations < 0 && r >= 0) + log_notice(ANSI_HIGHLIGHT_RED ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_NORMAL, p / 8, p % 8); - bit_toggle("test.journal", p); - } + bit_toggle("test.journal", p); } - log_info("Exiting..."); - assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); return 0; } int main(int argc, char *argv[]) { + const char *verification_key = NULL; + int max_iterations = 512; + + if (argc > 1) { + /* Don't limit the number of iterations when the verification key + * is provided on the command line, we want to do that only in CIs */ + verification_key = argv[1]; + max_iterations = -1; + } + assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0); - run_test(argc, argv); + run_test(verification_key, max_iterations); assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0); - run_test(argc, argv); + run_test(verification_key, max_iterations); + +#if HAVE_GCRYPT + /* If we're running without any arguments and we're compiled with gcrypt + * check the journal verification stuff with a valid key as well */ + if (argc <= 1) { + verification_key = "c262bd-85187f-0b1b04-877cc5/1c7af8-35a4e900"; + + assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0); + run_test(verification_key, max_iterations); + + assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0); + run_test(verification_key, max_iterations); + } +#endif return 0; } |