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 int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
44 /* This does various superficial tests about the length an
45 * possible field values. It does not follow any references to
48 if ((o->object.flags & OBJECT_COMPRESSED) &&
49 o->object.type != OBJECT_DATA)
52 switch (o->object.type) {
57 if (le64toh(o->data.entry_offset) == 0)
58 log_warning(OFSfmt": unused data (entry_offset==0)", offset);
60 if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
61 log_error(OFSfmt": bad n_entries: %"PRIu64, offset, o->data.n_entries);
65 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
66 log_error(OFSfmt": bad object size (<= %zu): %"PRIu64,
68 offsetof(DataObject, payload),
69 le64toh(o->object.size));
73 h1 = le64toh(o->data.hash);
75 if (o->object.flags & OBJECT_COMPRESSED) {
78 uint64_t alloc = 0, b_size;
80 if (!uncompress_blob(o->data.payload,
81 le64toh(o->object.size) - offsetof(Object, data.payload),
82 &b, &alloc, &b_size, 0)) {
83 log_error(OFSfmt": uncompression failed", offset);
87 h2 = hash64(b, b_size);
90 log_error("Compression is not supported");
91 return -EPROTONOSUPPORT;
94 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
97 log_error(OFSfmt": invalid hash (%08"PRIx64" vs. %08"PRIx64, offset, h1, h2);
101 if (!VALID64(o->data.next_hash_offset) ||
102 !VALID64(o->data.next_field_offset) ||
103 !VALID64(o->data.entry_offset) ||
104 !VALID64(o->data.entry_array_offset)) {
105 log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
107 o->data.next_hash_offset,
108 o->data.next_field_offset,
109 o->data.entry_offset,
110 o->data.entry_array_offset);
118 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
119 log_error(OFSfmt": bad field size (<= %zu): %"PRIu64,
121 offsetof(FieldObject, payload),
122 le64toh(o->object.size));
126 if (!VALID64(o->field.next_hash_offset) ||
127 !VALID64(o->field.head_data_offset)) {
128 log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
130 o->field.next_hash_offset,
131 o->field.head_data_offset);
137 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
138 log_error(OFSfmt": bad entry size (<= %zu): %"PRIu64,
140 offsetof(EntryObject, items),
141 le64toh(o->object.size));
145 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
146 log_error(OFSfmt": invalid number items in entry: %"PRIu64,
148 (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
152 if (le64toh(o->entry.seqnum) <= 0) {
153 log_error(OFSfmt": invalid entry seqnum: %"PRIx64,
155 le64toh(o->entry.seqnum));
159 if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
160 log_error(OFSfmt": invalid entry realtime timestamp: %"PRIu64,
162 le64toh(o->entry.realtime));
166 if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
167 log_error(OFSfmt": invalid entry monotonic timestamp: %"PRIu64,
169 le64toh(o->entry.monotonic));
173 for (i = 0; i < journal_file_entry_n_items(o); i++) {
174 if (o->entry.items[i].object_offset == 0 ||
175 !VALID64(o->entry.items[i].object_offset)) {
176 log_error(OFSfmt": invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
178 i, journal_file_entry_n_items(o),
179 o->entry.items[i].object_offset);
186 case OBJECT_DATA_HASH_TABLE:
187 case OBJECT_FIELD_HASH_TABLE:
188 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
189 (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
190 log_error(OFSfmt": invalid %s hash table size: %"PRIu64,
192 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
193 le64toh(o->object.size));
197 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
198 if (o->hash_table.items[i].head_hash_offset != 0 &&
199 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
200 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
202 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
203 i, journal_file_hash_table_n_items(o),
204 le64toh(o->hash_table.items[i].head_hash_offset));
207 if (o->hash_table.items[i].tail_hash_offset != 0 &&
208 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
209 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
211 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
212 i, journal_file_hash_table_n_items(o),
213 le64toh(o->hash_table.items[i].tail_hash_offset));
217 if ((o->hash_table.items[i].head_hash_offset != 0) !=
218 (o->hash_table.items[i].tail_hash_offset != 0)) {
219 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
221 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
222 i, journal_file_hash_table_n_items(o),
223 le64toh(o->hash_table.items[i].head_hash_offset),
224 le64toh(o->hash_table.items[i].tail_hash_offset));
231 case OBJECT_ENTRY_ARRAY:
232 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
233 (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
234 log_error(OFSfmt": invalid object entry array size: %"PRIu64,
236 le64toh(o->object.size));
240 if (!VALID64(o->entry_array.next_entry_array_offset)) {
241 log_error(OFSfmt": invalid object entry array next_entry_array_offset: "OFSfmt,
243 o->entry_array.next_entry_array_offset);
247 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
248 if (le64toh(o->entry_array.items[i]) != 0 &&
249 !VALID64(le64toh(o->entry_array.items[i]))) {
250 log_error(OFSfmt": invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
252 i, journal_file_entry_array_n_items(o),
253 le64toh(o->entry_array.items[i]));
260 if (le64toh(o->object.size) != sizeof(TagObject)) {
261 log_error(OFSfmt": invalid object tag size: %"PRIu64,
263 le64toh(o->object.size));
267 if (!VALID_EPOCH(o->tag.epoch)) {
268 log_error(OFSfmt": invalid object tag epoch: %"PRIu64,
280 static void draw_progress(uint64_t p, usec_t *last_usec) {
287 z = now(CLOCK_MONOTONIC);
290 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
295 n = (3 * columns()) / 4;
296 j = (n * (unsigned) p) / 65535ULL;
299 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
301 for (i = 0; i < j; i++)
302 fputs("\xe2\x96\x88", stdout);
304 fputs(ANSI_HIGHLIGHT_OFF, stdout);
306 for (i = 0; i < k; i++)
307 fputs("\xe2\x96\x91", stdout);
309 printf(" %3"PRIu64"%%", 100U * p / 65535U);
311 fputs("\r\x1B[?25h", stdout);
315 static void flush_progress(void) {
321 n = (3 * columns()) / 4;
325 for (i = 0; i < n + 5; i++)
332 static int write_uint64(int fd, uint64_t p) {
335 k = write(fd, &p, sizeof(p));
344 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
359 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
378 static int entry_points_to_data(
391 assert(entry_fd >= 0);
393 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
394 log_error("Data object references invalid entry at %"PRIu64, data_p);
398 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
402 n = journal_file_entry_n_items(o);
403 for (i = 0; i < n; i++)
404 if (le64toh(o->entry.items[i].object_offset) == data_p) {
410 log_error("Data object not referenced by linked entry at %"PRIu64, data_p);
414 /* Check if this entry is also in main entry array. Since the
415 * main entry array has already been verified we can rely on
419 n = le64toh(f->header->n_entries);
420 a = le64toh(f->header->entry_array_offset);
425 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
429 m = journal_file_entry_array_n_items(o);
432 if (entry_p <= le64toh(o->entry_array.items[u-1])) {
441 if (le64toh(o->entry_array.items[z]) == entry_p)
447 if (entry_p < le64toh(o->entry_array.items[z]))
453 log_error("Entry object doesn't exist in main entry array at %"PRIu64, entry_p);
458 a = le64toh(o->entry_array.next_entry_array_offset);
464 static int verify_data(
466 Object *o, uint64_t p,
467 int entry_fd, uint64_t n_entries,
468 int entry_array_fd, uint64_t n_entry_arrays) {
470 uint64_t i, n, a, last, q;
475 assert(entry_fd >= 0);
476 assert(entry_array_fd >= 0);
478 n = le64toh(o->data.n_entries);
479 a = le64toh(o->data.entry_array_offset);
481 /* Entry array means at least two objects */
483 log_error("Entry array present (entry_array_offset=%"PRIu64", but n_entries=%"PRIu64,
491 /* We already checked that earlier */
492 assert(o->data.entry_offset);
494 last = q = le64toh(o->data.entry_offset);
495 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
504 log_error("Array chain too short at %"PRIu64, p);
508 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
509 log_error("Invalid array at %"PRIu64, p);
513 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
517 next = le64toh(o->entry_array.next_entry_array_offset);
518 if (next != 0 && next <= a) {
519 log_error("Array chain has cycle at %"PRIu64, p);
523 m = journal_file_entry_array_n_items(o);
524 for (j = 0; i < n && j < m; i++, j++) {
526 q = le64toh(o->entry_array.items[j]);
528 log_error("Data object's entry array not sorted at %"PRIu64, p);
533 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
537 /* Pointer might have moved, reposition */
538 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
549 static int verify_hash_table(
551 int data_fd, uint64_t n_data,
552 int entry_fd, uint64_t n_entries,
553 int entry_array_fd, uint64_t n_entry_arrays,
555 bool show_progress) {
561 assert(data_fd >= 0);
562 assert(entry_fd >= 0);
563 assert(entry_array_fd >= 0);
566 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
567 for (i = 0; i < n; i++) {
568 uint64_t last = 0, p;
571 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
573 p = le64toh(f->data_hash_table[i].head_hash_offset);
578 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
579 log_error("Invalid data object at hash entry %"PRIu64" of %"PRIu64,
584 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
588 next = le64toh(o->data.next_hash_offset);
589 if (next != 0 && next <= p) {
590 log_error("Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
595 if (le64toh(o->data.hash) % n != i) {
596 log_error("Hash value mismatch in hash entry %"PRIu64" of %"PRIu64,
601 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
609 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
610 log_error("Tail hash pointer mismatch in hash table");
618 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
623 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
626 q = le64toh(f->data_hash_table[h].head_hash_offset);
633 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
637 q = le64toh(o->data.next_hash_offset);
643 static int verify_entry(
645 Object *o, uint64_t p,
646 int data_fd, uint64_t n_data) {
653 assert(data_fd >= 0);
655 n = journal_file_entry_n_items(o);
656 for (i = 0; i < n; i++) {
660 q = le64toh(o->entry.items[i].object_offset);
661 h = le64toh(o->entry.items[i].hash);
663 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
664 log_error("Invalid data object at entry %"PRIu64, p);
668 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
672 if (le64toh(u->data.hash) != h) {
673 log_error("Hash mismatch for data object at entry %"PRIu64, p);
677 r = data_object_in_hash_table(f, h, q);
681 log_error("Data object missing from hash at entry %"PRIu64, p);
689 static int verify_entry_array(
691 int data_fd, uint64_t n_data,
692 int entry_fd, uint64_t n_entries,
693 int entry_array_fd, uint64_t n_entry_arrays,
695 bool show_progress) {
697 uint64_t i = 0, a, n, last = 0;
701 assert(data_fd >= 0);
702 assert(entry_fd >= 0);
703 assert(entry_array_fd >= 0);
706 n = le64toh(f->header->n_entries);
707 a = le64toh(f->header->entry_array_offset);
713 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
716 log_error("Array chain too short at %"PRIu64" of %"PRIu64, i, n);
720 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
721 log_error("Invalid array at %"PRIu64" of %"PRIu64, i, n);
725 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
729 next = le64toh(o->entry_array.next_entry_array_offset);
730 if (next != 0 && next <= a) {
731 log_error("Array chain has cycle at %"PRIu64" of %"PRIu64, i, n);
735 m = journal_file_entry_array_n_items(o);
736 for (j = 0; i < n && j < m; i++, j++) {
739 p = le64toh(o->entry_array.items[j]);
741 log_error("Entry array not sorted at %"PRIu64" of %"PRIu64,
747 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
748 log_error("Invalid array entry at %"PRIu64" of %"PRIu64,
753 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
757 r = verify_entry(f, o, p, data_fd, n_data);
761 /* Pointer might have moved, reposition */
762 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
773 int journal_file_verify(
776 usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
777 bool show_progress) {
780 uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
782 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
783 sd_id128_t entry_boot_id;
784 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
785 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;
786 usec_t last_usec = 0;
787 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
788 char data_path[] = "/var/tmp/journal-data-XXXXXX",
789 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
790 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
794 uint64_t last_tag = 0;
800 r = journal_file_parse_verification_key(f, key);
802 log_error("Failed to parse seed.");
811 data_fd = mkostemp(data_path, O_CLOEXEC);
813 log_error("Failed to create data file: %m");
819 entry_fd = mkostemp(entry_path, O_CLOEXEC);
821 log_error("Failed to create entry file: %m");
827 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
828 if (entry_array_fd < 0) {
829 log_error("Failed to create entry array file: %m");
833 unlink(entry_array_path);
836 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
838 if (f->header->compatible_flags != 0)
841 log_error("Cannot verify file with unknown extensions.");
846 for (i = 0; i < sizeof(f->header->reserved); i++)
847 if (f->header->reserved[i] != 0) {
848 log_error("Reserved field in non-zero.");
853 /* First iteration: we go through all objects, verify the
854 * superficial structure, headers, hashes. */
856 p = le64toh(f->header->header_size);
859 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
861 r = journal_file_move_to_object(f, -1, p, &o);
863 log_error("Invalid object at "OFSfmt, p);
867 if (p > le64toh(f->header->tail_object_offset)) {
868 log_error("Invalid tail object pointer");
873 if (p == le64toh(f->header->tail_object_offset))
878 r = journal_file_object_verify(f, p, o);
880 log_error("Invalid object contents at "OFSfmt": %s", p, strerror(-r));
884 if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
885 log_error("Compressed object in file without compression at "OFSfmt, p);
890 switch (o->object.type) {
893 r = write_uint64(data_fd, p);
905 if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
906 log_error("First entry before first tag at "OFSfmt, p);
911 r = write_uint64(entry_fd, p);
915 if (le64toh(o->entry.realtime) < last_tag_realtime) {
916 log_error("Older entry after newer tag at "OFSfmt, p);
921 if (!entry_seqnum_set &&
922 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
923 log_error("Head entry sequence number incorrect at "OFSfmt, p);
928 if (entry_seqnum_set &&
929 entry_seqnum >= le64toh(o->entry.seqnum)) {
930 log_error("Entry sequence number out of synchronization at "OFSfmt, p);
935 entry_seqnum = le64toh(o->entry.seqnum);
936 entry_seqnum_set = true;
938 if (entry_monotonic_set &&
939 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
940 entry_monotonic > le64toh(o->entry.monotonic)) {
941 log_error("Entry timestamp out of synchronization at "OFSfmt, p);
946 entry_monotonic = le64toh(o->entry.monotonic);
947 entry_boot_id = o->entry.boot_id;
948 entry_monotonic_set = true;
950 if (!entry_realtime_set &&
951 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
952 log_error("Head entry realtime timestamp incorrect");
957 entry_realtime = le64toh(o->entry.realtime);
958 entry_realtime_set = true;
963 case OBJECT_DATA_HASH_TABLE:
964 if (n_data_hash_tables > 1) {
965 log_error("More than one data hash table at "OFSfmt, p);
970 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
971 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
972 log_error("Header fields for data hash table invalid");
977 n_data_hash_tables++;
980 case OBJECT_FIELD_HASH_TABLE:
981 if (n_field_hash_tables > 1) {
982 log_error("More than one field hash table at "OFSfmt, p);
987 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
988 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
989 log_error("Header fields for field hash table invalid");
994 n_field_hash_tables++;
997 case OBJECT_ENTRY_ARRAY:
998 r = write_uint64(entry_array_fd, p);
1002 if (p == le64toh(f->header->entry_array_offset)) {
1003 if (found_main_entry_array) {
1004 log_error("More than one main entry array at "OFSfmt, p);
1009 found_main_entry_array = true;
1016 if (!JOURNAL_HEADER_SEALED(f->header)) {
1017 log_error("Tag object in file without sealing at "OFSfmt, p);
1022 if (le64toh(o->tag.seqnum) != n_tags + 1) {
1023 log_error("Tag sequence number out of synchronization at "OFSfmt, p);
1028 if (le64toh(o->tag.epoch) < last_epoch) {
1029 log_error("Epoch sequence out of synchronization at "OFSfmt, p);
1038 log_debug("Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
1040 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
1041 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
1042 log_error("Tag/entry realtime timestamp out of synchronization at "OFSfmt, p);
1047 /* OK, now we know the epoch. So let's now set
1048 * it, and calculate the HMAC for everything
1049 * since the last tag. */
1050 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
1054 r = journal_file_hmac_start(f);
1058 if (last_tag == 0) {
1059 r = journal_file_hmac_put_header(f);
1063 q = le64toh(f->header->header_size);
1068 r = journal_file_move_to_object(f, -1, q, &o);
1072 r = journal_file_hmac_put_object(f, -1, o, q);
1076 q = q + ALIGN64(le64toh(o->object.size));
1079 /* Position might have changed, let's reposition things */
1080 r = journal_file_move_to_object(f, -1, p, &o);
1084 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1085 log_error("Tag failed verification at "OFSfmt, p);
1090 f->hmac_running = false;
1091 last_tag_realtime = rt;
1092 last_sealed_realtime = entry_realtime;
1095 last_tag = p + ALIGN64(le64toh(o->object.size));
1098 last_epoch = le64toh(o->tag.epoch);
1107 if (p == le64toh(f->header->tail_object_offset))
1110 p = p + ALIGN64(le64toh(o->object.size));
1114 log_error("Tail object pointer dead");
1119 if (n_objects != le64toh(f->header->n_objects)) {
1120 log_error("Object number mismatch");
1125 if (n_entries != le64toh(f->header->n_entries)) {
1126 log_error("Entry number mismatch");
1131 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1132 n_data != le64toh(f->header->n_data)) {
1133 log_error("Data number mismatch");
1138 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1139 n_fields != le64toh(f->header->n_fields)) {
1140 log_error("Field number mismatch");
1145 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1146 n_tags != le64toh(f->header->n_tags)) {
1147 log_error("Tag number mismatch");
1152 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1153 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1154 log_error("Entry array number mismatch");
1159 if (n_data_hash_tables != 1) {
1160 log_error("Missing data hash table");
1165 if (n_field_hash_tables != 1) {
1166 log_error("Missing field hash table");
1171 if (!found_main_entry_array) {
1172 log_error("Missing entry array");
1177 if (entry_seqnum_set &&
1178 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1179 log_error("Invalid tail seqnum");
1184 if (entry_monotonic_set &&
1185 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1186 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1187 log_error("Invalid tail monotonic timestamp");
1192 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1193 log_error("Invalid tail realtime timestamp");
1198 /* Second iteration: we follow all objects referenced from the
1199 * two entry points: the object hash table and the entry
1200 * array. We also check that everything referenced (directly
1201 * or indirectly) in the data hash table also exists in the
1202 * entry array, and vice versa. Note that we do not care for
1203 * unreferenced objects. We only care that everything that is
1204 * referenced is consistent. */
1206 r = verify_entry_array(f,
1208 entry_fd, n_entries,
1209 entry_array_fd, n_entry_arrays,
1215 r = verify_hash_table(f,
1217 entry_fd, n_entries,
1218 entry_array_fd, n_entry_arrays,
1227 mmap_cache_close_fd(f->mmap, data_fd);
1228 mmap_cache_close_fd(f->mmap, entry_fd);
1229 mmap_cache_close_fd(f->mmap, entry_array_fd);
1231 close_nointr_nofail(data_fd);
1232 close_nointr_nofail(entry_fd);
1233 close_nointr_nofail(entry_array_fd);
1235 if (first_contained)
1236 *first_contained = le64toh(f->header->head_entry_realtime);
1238 *last_validated = last_sealed_realtime;
1240 *last_contained = le64toh(f->header->tail_entry_realtime);
1248 log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
1251 (unsigned long long) f->last_stat.st_size,
1252 100 * p / f->last_stat.st_size);
1255 mmap_cache_close_fd(f->mmap, data_fd);
1256 close_nointr_nofail(data_fd);
1259 if (entry_fd >= 0) {
1260 mmap_cache_close_fd(f->mmap, entry_fd);
1261 close_nointr_nofail(entry_fd);
1264 if (entry_array_fd >= 0) {
1265 mmap_cache_close_fd(f->mmap, entry_array_fd);
1266 close_nointr_nofail(entry_array_fd);