1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include "journal-def.h"
30 #include "journal-file.h"
31 #include "journal-authenticate.h"
32 #include "journal-verify.h"
37 static void draw_progress(uint64_t p, usec_t *last_usec) {
44 z = now(CLOCK_MONOTONIC);
47 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
52 n = (3 * columns()) / 4;
53 j = (n * (unsigned) p) / 65535ULL;
56 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
58 for (i = 0; i < j; i++)
59 fputs("\xe2\x96\x88", stdout);
61 fputs(ANSI_HIGHLIGHT_OFF, stdout);
63 for (i = 0; i < k; i++)
64 fputs("\xe2\x96\x91", stdout);
66 printf(" %3"PRIu64"%%", 100U * p / 65535U);
68 fputs("\r\x1B[?25h", stdout);
72 static void flush_progress(void) {
78 n = (3 * columns()) / 4;
82 for (i = 0; i < n + 5; i++)
89 #define debug(_offset, _fmt, ...) do{ \
91 log_debug(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \
94 #define warning(_offset, _fmt, ...) do{ \
96 log_warning(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \
99 #define error(_offset, _fmt, ...) do{ \
101 log_error(OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \
104 static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
111 /* This does various superficial tests about the length an
112 * possible field values. It does not follow any references to
115 if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
116 o->object.type != OBJECT_DATA)
119 switch (o->object.type) {
125 if (le64toh(o->data.entry_offset) == 0)
126 warning(offset, "unused data (entry_offset==0)");
128 if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
129 error(offset, "bad n_entries: %"PRIu64, o->data.n_entries);
133 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
134 error(offset, "bad object size (<= %zu): %"PRIu64,
135 offsetof(DataObject, payload),
136 le64toh(o->object.size));
140 h1 = le64toh(o->data.hash);
142 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
144 _cleanup_free_ void *b = NULL;
145 size_t alloc = 0, b_size;
147 r = decompress_blob(compression,
149 le64toh(o->object.size) - offsetof(Object, data.payload),
150 &b, &alloc, &b_size, 0);
152 error(offset, "%s decompression failed: %s",
153 object_compressed_to_string(compression), strerror(-r));
157 h2 = hash64(b, b_size);
159 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
162 error(offset, "invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2);
166 if (!VALID64(o->data.next_hash_offset) ||
167 !VALID64(o->data.next_field_offset) ||
168 !VALID64(o->data.entry_offset) ||
169 !VALID64(o->data.entry_array_offset)) {
170 error(offset, "invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
171 o->data.next_hash_offset,
172 o->data.next_field_offset,
173 o->data.entry_offset,
174 o->data.entry_array_offset);
182 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
184 "bad field size (<= %zu): %"PRIu64,
185 offsetof(FieldObject, payload),
186 le64toh(o->object.size));
190 if (!VALID64(o->field.next_hash_offset) ||
191 !VALID64(o->field.head_data_offset)) {
193 "invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
194 o->field.next_hash_offset,
195 o->field.head_data_offset);
201 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
203 "bad entry size (<= %zu): %"PRIu64,
204 offsetof(EntryObject, items),
205 le64toh(o->object.size));
209 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
211 "invalid number items in entry: %"PRIu64,
212 (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
216 if (le64toh(o->entry.seqnum) <= 0) {
218 "invalid entry seqnum: %"PRIx64,
219 le64toh(o->entry.seqnum));
223 if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
225 "invalid entry realtime timestamp: %"PRIu64,
226 le64toh(o->entry.realtime));
230 if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
232 "invalid entry monotonic timestamp: %"PRIu64,
233 le64toh(o->entry.monotonic));
237 for (i = 0; i < journal_file_entry_n_items(o); i++) {
238 if (o->entry.items[i].object_offset == 0 ||
239 !VALID64(o->entry.items[i].object_offset)) {
241 "invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
242 i, journal_file_entry_n_items(o),
243 o->entry.items[i].object_offset);
250 case OBJECT_DATA_HASH_TABLE:
251 case OBJECT_FIELD_HASH_TABLE:
252 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
253 (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
255 "invalid %s hash table size: %"PRIu64,
256 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
257 le64toh(o->object.size));
261 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
262 if (o->hash_table.items[i].head_hash_offset != 0 &&
263 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
265 "invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
266 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
267 i, journal_file_hash_table_n_items(o),
268 le64toh(o->hash_table.items[i].head_hash_offset));
271 if (o->hash_table.items[i].tail_hash_offset != 0 &&
272 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
274 "invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
275 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
276 i, journal_file_hash_table_n_items(o),
277 le64toh(o->hash_table.items[i].tail_hash_offset));
281 if ((o->hash_table.items[i].head_hash_offset != 0) !=
282 (o->hash_table.items[i].tail_hash_offset != 0)) {
284 "invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
285 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
286 i, journal_file_hash_table_n_items(o),
287 le64toh(o->hash_table.items[i].head_hash_offset),
288 le64toh(o->hash_table.items[i].tail_hash_offset));
295 case OBJECT_ENTRY_ARRAY:
296 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
297 (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
299 "invalid object entry array size: %"PRIu64,
300 le64toh(o->object.size));
304 if (!VALID64(o->entry_array.next_entry_array_offset)) {
306 "invalid object entry array next_entry_array_offset: "OFSfmt,
307 o->entry_array.next_entry_array_offset);
311 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
312 if (le64toh(o->entry_array.items[i]) != 0 &&
313 !VALID64(le64toh(o->entry_array.items[i]))) {
315 "invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
316 i, journal_file_entry_array_n_items(o),
317 le64toh(o->entry_array.items[i]));
324 if (le64toh(o->object.size) != sizeof(TagObject)) {
326 "invalid object tag size: %"PRIu64,
327 le64toh(o->object.size));
331 if (!VALID_EPOCH(o->tag.epoch)) {
333 "invalid object tag epoch: %"PRIu64,
344 static int write_uint64(int fd, uint64_t p) {
347 k = write(fd, &p, sizeof(p));
356 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
371 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
390 static int entry_points_to_data(
403 assert(entry_fd >= 0);
405 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
407 "data object references invalid entry at "OFSfmt, entry_p);
411 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
415 n = journal_file_entry_n_items(o);
416 for (i = 0; i < n; i++)
417 if (le64toh(o->entry.items[i].object_offset) == data_p) {
424 "data object at "OFSfmt" not referenced by linked entry", data_p);
428 /* Check if this entry is also in main entry array. Since the
429 * main entry array has already been verified we can rely on
430 * its consistency. */
433 n = le64toh(f->header->n_entries);
434 a = le64toh(f->header->entry_array_offset);
439 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
443 m = journal_file_entry_array_n_items(o);
446 if (entry_p <= le64toh(o->entry_array.items[u-1])) {
455 if (le64toh(o->entry_array.items[z]) == entry_p)
461 if (entry_p < le64toh(o->entry_array.items[z]))
467 error(entry_p, "entry object doesn't exist in main entry array");
472 a = le64toh(o->entry_array.next_entry_array_offset);
478 static int verify_data(
480 Object *o, uint64_t p,
481 int entry_fd, uint64_t n_entries,
482 int entry_array_fd, uint64_t n_entry_arrays) {
484 uint64_t i, n, a, last, q;
489 assert(entry_fd >= 0);
490 assert(entry_array_fd >= 0);
492 n = le64toh(o->data.n_entries);
493 a = le64toh(o->data.entry_array_offset);
495 /* Entry array means at least two objects */
498 "entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")",
506 /* We already checked that earlier */
507 assert(o->data.entry_offset);
509 last = q = le64toh(o->data.entry_offset);
510 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
519 error(p, "array chain too short");
523 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
524 error(p, "invalid array offset "OFSfmt, a);
528 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
532 next = le64toh(o->entry_array.next_entry_array_offset);
533 if (next != 0 && next <= a) {
534 error(p, "array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")",
539 m = journal_file_entry_array_n_items(o);
540 for (j = 0; i < n && j < m; i++, j++) {
542 q = le64toh(o->entry_array.items[j]);
544 error(p, "data object's entry array not sorted");
549 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
553 /* Pointer might have moved, reposition */
554 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
565 static int verify_hash_table(
567 int data_fd, uint64_t n_data,
568 int entry_fd, uint64_t n_entries,
569 int entry_array_fd, uint64_t n_entry_arrays,
571 bool show_progress) {
577 assert(data_fd >= 0);
578 assert(entry_fd >= 0);
579 assert(entry_array_fd >= 0);
582 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
583 for (i = 0; i < n; i++) {
584 uint64_t last = 0, p;
587 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
589 p = le64toh(f->data_hash_table[i].head_hash_offset);
594 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
595 error(p, "invalid data object at hash entry %"PRIu64" of %"PRIu64,
600 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
604 next = le64toh(o->data.next_hash_offset);
605 if (next != 0 && next <= p) {
606 error(p, "hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
611 if (le64toh(o->data.hash) % n != i) {
612 error(p, "hash value mismatch in hash entry %"PRIu64" of %"PRIu64,
617 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
625 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
626 error(p, "tail hash pointer mismatch in hash table");
634 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
639 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
642 q = le64toh(f->data_hash_table[h].head_hash_offset);
649 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
653 q = le64toh(o->data.next_hash_offset);
659 static int verify_entry(
661 Object *o, uint64_t p,
662 int data_fd, uint64_t n_data) {
669 assert(data_fd >= 0);
671 n = journal_file_entry_n_items(o);
672 for (i = 0; i < n; i++) {
676 q = le64toh(o->entry.items[i].object_offset);
677 h = le64toh(o->entry.items[i].hash);
679 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
680 error(p, "invalid data object of entry");
684 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
688 if (le64toh(u->data.hash) != h) {
689 error(p, "hash mismatch for data object of entry");
693 r = data_object_in_hash_table(f, h, q);
697 error(p, "data object missing from hash table");
705 static int verify_entry_array(
707 int data_fd, uint64_t n_data,
708 int entry_fd, uint64_t n_entries,
709 int entry_array_fd, uint64_t n_entry_arrays,
711 bool show_progress) {
713 uint64_t i = 0, a, n, last = 0;
717 assert(data_fd >= 0);
718 assert(entry_fd >= 0);
719 assert(entry_array_fd >= 0);
722 n = le64toh(f->header->n_entries);
723 a = le64toh(f->header->entry_array_offset);
729 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
732 error(a, "array chain too short at %"PRIu64" of %"PRIu64, i, n);
736 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
737 error(a, "invalid array %"PRIu64" of %"PRIu64, i, n);
741 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
745 next = le64toh(o->entry_array.next_entry_array_offset);
746 if (next != 0 && next <= a) {
748 "array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")",
753 m = journal_file_entry_array_n_items(o);
754 for (j = 0; i < n && j < m; i++, j++) {
757 p = le64toh(o->entry_array.items[j]);
759 error(a, "entry array not sorted at %"PRIu64" of %"PRIu64,
765 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
766 error(a, "invalid array entry at %"PRIu64" of %"PRIu64,
771 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
775 r = verify_entry(f, o, p, data_fd, n_data);
779 /* Pointer might have moved, reposition */
780 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
791 int journal_file_verify(
794 usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
795 bool show_progress) {
798 uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
800 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
801 sd_id128_t entry_boot_id;
802 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
803 uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0, n_tags = 0;
804 usec_t last_usec = 0;
805 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
807 bool found_last = false;
809 uint64_t last_tag = 0;
815 r = journal_file_parse_verification_key(f, key);
817 log_error("Failed to parse seed.");
826 data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
828 log_error_errno(errno, "Failed to create data file: %m");
833 entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
835 log_error_errno(errno, "Failed to create entry file: %m");
840 entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
841 if (entry_array_fd < 0) {
842 log_error_errno(errno, "Failed to create entry array file: %m");
847 if (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SUPPORTED) {
848 log_error("Cannot verify file with unknown extensions.");
853 for (i = 0; i < sizeof(f->header->reserved); i++)
854 if (f->header->reserved[i] != 0) {
855 error(offsetof(Header, reserved[i]), "reserved field is non-zero");
860 /* First iteration: we go through all objects, verify the
861 * superficial structure, headers, hashes. */
863 p = le64toh(f->header->header_size);
866 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
868 r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
870 error(p, "invalid object");
874 if (p > le64toh(f->header->tail_object_offset)) {
875 error(offsetof(Header, tail_object_offset), "invalid tail object pointer");
880 if (p == le64toh(f->header->tail_object_offset))
885 r = journal_file_object_verify(f, p, o);
887 error(p, "invalid object contents: %s", strerror(-r));
891 if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
892 (o->object.flags & OBJECT_COMPRESSED_LZ4)) {
893 error(p, "objected with double compression");
898 if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) {
899 error(p, "XZ compressed object in file without XZ compression");
904 if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) {
905 error(p, "LZ4 compressed object in file without LZ4 compression");
910 switch (o->object.type) {
913 r = write_uint64(data_fd, p);
925 if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
926 error(p, "first entry before first tag");
931 r = write_uint64(entry_fd, p);
935 if (le64toh(o->entry.realtime) < last_tag_realtime) {
936 error(p, "older entry after newer tag");
941 if (!entry_seqnum_set &&
942 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
943 error(p, "head entry sequence number incorrect");
948 if (entry_seqnum_set &&
949 entry_seqnum >= le64toh(o->entry.seqnum)) {
950 error(p, "entry sequence number out of synchronization");
955 entry_seqnum = le64toh(o->entry.seqnum);
956 entry_seqnum_set = true;
958 if (entry_monotonic_set &&
959 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
960 entry_monotonic > le64toh(o->entry.monotonic)) {
961 error(p, "entry timestamp out of synchronization");
966 entry_monotonic = le64toh(o->entry.monotonic);
967 entry_boot_id = o->entry.boot_id;
968 entry_monotonic_set = true;
970 if (!entry_realtime_set &&
971 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
972 error(p, "head entry realtime timestamp incorrect");
977 entry_realtime = le64toh(o->entry.realtime);
978 entry_realtime_set = true;
983 case OBJECT_DATA_HASH_TABLE:
984 if (n_data_hash_tables > 1) {
985 error(p, "more than one data hash table");
990 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
991 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
992 error(p, "header fields for data hash table invalid");
997 n_data_hash_tables++;
1000 case OBJECT_FIELD_HASH_TABLE:
1001 if (n_field_hash_tables > 1) {
1002 error(p, "more than one field hash table");
1007 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
1008 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
1009 error(p, "header fields for field hash table invalid");
1014 n_field_hash_tables++;
1017 case OBJECT_ENTRY_ARRAY:
1018 r = write_uint64(entry_array_fd, p);
1022 if (p == le64toh(f->header->entry_array_offset)) {
1023 if (found_main_entry_array) {
1024 error(p, "more than one main entry array");
1029 found_main_entry_array = true;
1036 if (!JOURNAL_HEADER_SEALED(f->header)) {
1037 error(p, "tag object in file without sealing");
1042 if (le64toh(o->tag.seqnum) != n_tags + 1) {
1043 error(p, "tag sequence number out of synchronization");
1048 if (le64toh(o->tag.epoch) < last_epoch) {
1049 error(p, "epoch sequence out of synchronization");
1058 debug(p, "checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
1060 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
1061 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
1062 error(p, "tag/entry realtime timestamp out of synchronization");
1067 /* OK, now we know the epoch. So let's now set
1068 * it, and calculate the HMAC for everything
1069 * since the last tag. */
1070 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
1074 r = journal_file_hmac_start(f);
1078 if (last_tag == 0) {
1079 r = journal_file_hmac_put_header(f);
1083 q = le64toh(f->header->header_size);
1088 r = journal_file_move_to_object(f, OBJECT_UNUSED, q, &o);
1092 r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q);
1096 q = q + ALIGN64(le64toh(o->object.size));
1099 /* Position might have changed, let's reposition things */
1100 r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
1104 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1105 error(p, "tag failed verification");
1110 f->hmac_running = false;
1111 last_tag_realtime = rt;
1112 last_sealed_realtime = entry_realtime;
1115 last_tag = p + ALIGN64(le64toh(o->object.size));
1118 last_epoch = le64toh(o->tag.epoch);
1127 if (p == le64toh(f->header->tail_object_offset))
1130 p = p + ALIGN64(le64toh(o->object.size));
1134 error(le64toh(f->header->tail_object_offset), "tail object pointer dead");
1139 if (n_objects != le64toh(f->header->n_objects)) {
1140 error(offsetof(Header, n_objects), "object number mismatch");
1145 if (n_entries != le64toh(f->header->n_entries)) {
1146 error(offsetof(Header, n_entries), "entry number mismatch");
1151 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1152 n_data != le64toh(f->header->n_data)) {
1153 error(offsetof(Header, n_data), "data number mismatch");
1158 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1159 n_fields != le64toh(f->header->n_fields)) {
1160 error(offsetof(Header, n_fields), "field number mismatch");
1165 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1166 n_tags != le64toh(f->header->n_tags)) {
1167 error(offsetof(Header, n_tags), "tag number mismatch");
1172 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1173 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1174 error(offsetof(Header, n_entry_arrays), "entry array number mismatch");
1179 if (n_data_hash_tables != 1) {
1180 error(0, "missing data hash table");
1185 if (n_field_hash_tables != 1) {
1186 error(0, "missing field hash table");
1191 if (!found_main_entry_array) {
1192 error(0, "missing entry array");
1197 if (entry_seqnum_set &&
1198 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1199 error(offsetof(Header, tail_entry_seqnum), "invalid tail seqnum");
1204 if (entry_monotonic_set &&
1205 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1206 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1207 error(0, "invalid tail monotonic timestamp");
1212 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1213 error(0, "invalid tail realtime timestamp");
1218 /* Second iteration: we follow all objects referenced from the
1219 * two entry points: the object hash table and the entry
1220 * array. We also check that everything referenced (directly
1221 * or indirectly) in the data hash table also exists in the
1222 * entry array, and vice versa. Note that we do not care for
1223 * unreferenced objects. We only care that everything that is
1224 * referenced is consistent. */
1226 r = verify_entry_array(f,
1228 entry_fd, n_entries,
1229 entry_array_fd, n_entry_arrays,
1235 r = verify_hash_table(f,
1237 entry_fd, n_entries,
1238 entry_array_fd, n_entry_arrays,
1247 mmap_cache_close_fd(f->mmap, data_fd);
1248 mmap_cache_close_fd(f->mmap, entry_fd);
1249 mmap_cache_close_fd(f->mmap, entry_array_fd);
1251 safe_close(data_fd);
1252 safe_close(entry_fd);
1253 safe_close(entry_array_fd);
1255 if (first_contained)
1256 *first_contained = le64toh(f->header->head_entry_realtime);
1258 *last_validated = last_sealed_realtime;
1260 *last_contained = le64toh(f->header->tail_entry_realtime);
1268 log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
1271 (unsigned long long) f->last_stat.st_size,
1272 100 * p / f->last_stat.st_size);
1275 mmap_cache_close_fd(f->mmap, data_fd);
1276 safe_close(data_fd);
1279 if (entry_fd >= 0) {
1280 mmap_cache_close_fd(f->mmap, entry_fd);
1281 safe_close(entry_fd);
1284 if (entry_array_fd >= 0) {
1285 mmap_cache_close_fd(f->mmap, entry_array_fd);
1286 safe_close(entry_array_fd);