Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <fcntl.h>
4 : #include <stdio.h>
5 : #include <unistd.h>
6 :
7 : #include "chattr-util.h"
8 : #include "fd-util.h"
9 : #include "io-util.h"
10 : #include "journal-file.h"
11 : #include "journal-verify.h"
12 : #include "log.h"
13 : #include "rm-rf.h"
14 : #include "terminal-util.h"
15 : #include "tests.h"
16 : #include "util.h"
17 :
18 : #define N_ENTRIES 6000
19 : #define RANDOM_RANGE 77
20 :
21 0 : static void bit_toggle(const char *fn, uint64_t p) {
22 : uint8_t b;
23 : ssize_t r;
24 : int fd;
25 :
26 0 : fd = open(fn, O_RDWR|O_CLOEXEC);
27 0 : assert_se(fd >= 0);
28 :
29 0 : r = pread(fd, &b, 1, p/8);
30 0 : assert_se(r == 1);
31 :
32 0 : b ^= 1 << (p % 8);
33 :
34 0 : r = pwrite(fd, &b, 1, p/8);
35 0 : assert_se(r == 1);
36 :
37 0 : safe_close(fd);
38 0 : }
39 :
40 0 : static int raw_verify(const char *fn, const char *verification_key) {
41 : JournalFile *f;
42 : int r;
43 :
44 0 : r = journal_file_open(-1, fn, O_RDONLY, 0666, true, (uint64_t) -1, !!verification_key, NULL, NULL, NULL, NULL, &f);
45 0 : if (r < 0)
46 0 : return r;
47 :
48 0 : r = journal_file_verify(f, verification_key, NULL, NULL, NULL, false);
49 0 : (void) journal_file_close(f);
50 :
51 0 : return r;
52 : }
53 :
54 1 : int main(int argc, char *argv[]) {
55 1 : char t[] = "/var/tmp/journal-XXXXXX";
56 : unsigned n;
57 : JournalFile *f;
58 1 : const char *verification_key = argv[1];
59 1 : usec_t from = 0, to = 0, total = 0;
60 : char a[FORMAT_TIMESTAMP_MAX];
61 : char b[FORMAT_TIMESTAMP_MAX];
62 : char c[FORMAT_TIMESPAN_MAX];
63 : struct stat st;
64 : uint64_t p;
65 :
66 : /* journal_file_open requires a valid machine id */
67 1 : if (access("/etc/machine-id", F_OK) != 0)
68 0 : return log_tests_skipped("/etc/machine-id not found");
69 :
70 1 : test_setup_logging(LOG_DEBUG);
71 :
72 1 : assert_se(mkdtemp(t));
73 1 : assert_se(chdir(t) >= 0);
74 1 : (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
75 :
76 1 : log_info("Generating...");
77 :
78 1 : assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
79 :
80 6001 : for (n = 0; n < N_ENTRIES; n++) {
81 : struct iovec iovec;
82 : struct dual_timestamp ts;
83 : char *test;
84 :
85 6000 : dual_timestamp_get(&ts);
86 :
87 6000 : assert_se(asprintf(&test, "RANDOM=%lu", random() % RANDOM_RANGE));
88 :
89 6000 : iovec = IOVEC_MAKE_STRING(test);
90 :
91 6000 : assert_se(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0);
92 :
93 6000 : free(test);
94 : }
95 :
96 1 : (void) journal_file_close(f);
97 :
98 1 : log_info("Verifying...");
99 :
100 1 : assert_se(journal_file_open(-1, "test.journal", O_RDONLY, 0666, true, (uint64_t) -1, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
101 : /* journal_file_print_header(f); */
102 1 : journal_file_dump(f);
103 :
104 1 : assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0);
105 :
106 1 : if (verification_key && JOURNAL_HEADER_SEALED(f->header))
107 0 : log_info("=> Validated from %s to %s, %s missing",
108 : format_timestamp(a, sizeof(a), from),
109 : format_timestamp(b, sizeof(b), to),
110 : format_timespan(c, sizeof(c), total > to ? total - to : 0, 0));
111 :
112 1 : (void) journal_file_close(f);
113 :
114 1 : if (verification_key) {
115 0 : log_info("Toggling bits...");
116 :
117 0 : assert_se(stat("test.journal", &st) >= 0);
118 :
119 0 : for (p = 38448*8+0; p < ((uint64_t) st.st_size * 8); p ++) {
120 0 : bit_toggle("test.journal", p);
121 :
122 0 : log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8);
123 :
124 0 : if (raw_verify("test.journal", verification_key) >= 0)
125 0 : log_notice(ANSI_HIGHLIGHT_RED ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_NORMAL, p / 8, p % 8);
126 :
127 0 : bit_toggle("test.journal", p);
128 : }
129 : }
130 :
131 1 : log_info("Exiting...");
132 :
133 1 : assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
134 :
135 1 : return 0;
136 : }
|