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 /* Use six characters to cover the offsets common in smallish journal
38 * files without adding to many zeros. */
39 #define OFSfmt "%06"PRIx64
41 static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
48 /* This does various superficial tests about the length an
49 * possible field values. It does not follow any references to
52 if ((o->object.flags & OBJECT_COMPRESSED) &&
53 o->object.type != OBJECT_DATA)
56 switch (o->object.type) {
61 if (le64toh(o->data.entry_offset) == 0)
62 log_warning(OFSfmt": unused data (entry_offset==0)", offset);
64 if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
65 log_error(OFSfmt": bad n_entries: %"PRIu64, offset, o->data.n_entries);
69 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
70 log_error(OFSfmt": bad object size (<= %zu): %"PRIu64,
72 offsetof(DataObject, payload),
73 le64toh(o->object.size));
77 h1 = le64toh(o->data.hash);
79 if (o->object.flags & OBJECT_COMPRESSED) {
82 uint64_t alloc = 0, b_size;
84 if (!uncompress_blob(o->data.payload,
85 le64toh(o->object.size) - offsetof(Object, data.payload),
86 &b, &alloc, &b_size, 0)) {
87 log_error(OFSfmt": uncompression failed", offset);
91 h2 = hash64(b, b_size);
94 log_error("Compression is not supported");
95 return -EPROTONOSUPPORT;
98 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
101 log_error(OFSfmt": invalid hash (%08"PRIx64" vs. %08"PRIx64, offset, h1, h2);
105 if (!VALID64(o->data.next_hash_offset) ||
106 !VALID64(o->data.next_field_offset) ||
107 !VALID64(o->data.entry_offset) ||
108 !VALID64(o->data.entry_array_offset)) {
109 log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
111 o->data.next_hash_offset,
112 o->data.next_field_offset,
113 o->data.entry_offset,
114 o->data.entry_array_offset);
122 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
123 log_error(OFSfmt": bad field size (<= %zu): %"PRIu64,
125 offsetof(FieldObject, payload),
126 le64toh(o->object.size));
130 if (!VALID64(o->field.next_hash_offset) ||
131 !VALID64(o->field.head_data_offset)) {
132 log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
134 o->field.next_hash_offset,
135 o->field.head_data_offset);
141 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
142 log_error(OFSfmt": bad entry size (<= %zu): %"PRIu64,
144 offsetof(EntryObject, items),
145 le64toh(o->object.size));
149 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
150 log_error(OFSfmt": invalid number items in entry: %"PRIu64,
152 (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
156 if (le64toh(o->entry.seqnum) <= 0) {
157 log_error(OFSfmt": invalid entry seqnum: %"PRIx64,
159 le64toh(o->entry.seqnum));
163 if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
164 log_error(OFSfmt": invalid entry realtime timestamp: %"PRIu64,
166 le64toh(o->entry.realtime));
170 if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
171 log_error(OFSfmt": invalid entry monotonic timestamp: %"PRIu64,
173 le64toh(o->entry.monotonic));
177 for (i = 0; i < journal_file_entry_n_items(o); i++) {
178 if (o->entry.items[i].object_offset == 0 ||
179 !VALID64(o->entry.items[i].object_offset)) {
180 log_error(OFSfmt": invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
182 i, journal_file_entry_n_items(o),
183 o->entry.items[i].object_offset);
190 case OBJECT_DATA_HASH_TABLE:
191 case OBJECT_FIELD_HASH_TABLE:
192 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
193 (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
194 log_error(OFSfmt": invalid %s hash table size: %"PRIu64,
196 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
197 le64toh(o->object.size));
201 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
202 if (o->hash_table.items[i].head_hash_offset != 0 &&
203 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
204 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
206 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
207 i, journal_file_hash_table_n_items(o),
208 le64toh(o->hash_table.items[i].head_hash_offset));
211 if (o->hash_table.items[i].tail_hash_offset != 0 &&
212 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
213 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
215 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
216 i, journal_file_hash_table_n_items(o),
217 le64toh(o->hash_table.items[i].tail_hash_offset));
221 if ((o->hash_table.items[i].head_hash_offset != 0) !=
222 (o->hash_table.items[i].tail_hash_offset != 0)) {
223 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
225 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
226 i, journal_file_hash_table_n_items(o),
227 le64toh(o->hash_table.items[i].head_hash_offset),
228 le64toh(o->hash_table.items[i].tail_hash_offset));
235 case OBJECT_ENTRY_ARRAY:
236 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
237 (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
238 log_error(OFSfmt": invalid object entry array size: %"PRIu64,
240 le64toh(o->object.size));
244 if (!VALID64(o->entry_array.next_entry_array_offset)) {
245 log_error(OFSfmt": invalid object entry array next_entry_array_offset: "OFSfmt,
247 o->entry_array.next_entry_array_offset);
251 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
252 if (o->entry_array.items[i] != 0 &&
253 !VALID64(o->entry_array.items[i])) {
254 log_error(OFSfmt": invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
256 i, journal_file_entry_array_n_items(o),
257 o->entry_array.items[i]);
264 if (le64toh(o->object.size) != sizeof(TagObject)) {
265 log_error(OFSfmt": invalid object tag size: %"PRIu64,
267 le64toh(o->object.size));
271 if (!VALID_EPOCH(o->tag.epoch)) {
272 log_error(OFSfmt": invalid object tag epoch: %"PRIu64,
284 static void draw_progress(uint64_t p, usec_t *last_usec) {
291 z = now(CLOCK_MONOTONIC);
294 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
299 n = (3 * columns()) / 4;
300 j = (n * (unsigned) p) / 65535ULL;
303 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
305 for (i = 0; i < j; i++)
306 fputs("\xe2\x96\x88", stdout);
308 fputs(ANSI_HIGHLIGHT_OFF, stdout);
310 for (i = 0; i < k; i++)
311 fputs("\xe2\x96\x91", stdout);
313 printf(" %3"PRIu64"%%", 100U * p / 65535U);
315 fputs("\r\x1B[?25h", stdout);
319 static void flush_progress(void) {
325 n = (3 * columns()) / 4;
329 for (i = 0; i < n + 5; i++)
336 static int write_uint64(int fd, uint64_t p) {
339 k = write(fd, &p, sizeof(p));
348 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
363 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
382 static int entry_points_to_data(
395 assert(entry_fd >= 0);
397 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
398 log_error("Data object references invalid entry at %"PRIu64, data_p);
402 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
406 n = journal_file_entry_n_items(o);
407 for (i = 0; i < n; i++)
408 if (le64toh(o->entry.items[i].object_offset) == data_p) {
414 log_error("Data object not referenced by linked entry at %"PRIu64, data_p);
418 /* Check if this entry is also in main entry array. Since the
419 * main entry array has already been verified we can rely on
423 n = le64toh(f->header->n_entries);
424 a = le64toh(f->header->entry_array_offset);
429 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
433 m = journal_file_entry_array_n_items(o);
436 if (entry_p <= le64toh(o->entry_array.items[u-1])) {
445 if (le64toh(o->entry_array.items[z]) == entry_p)
451 if (entry_p < le64toh(o->entry_array.items[z]))
457 log_error("Entry object doesn't exist in main entry array at %"PRIu64, entry_p);
462 a = le64toh(o->entry_array.next_entry_array_offset);
468 static int verify_data(
470 Object *o, uint64_t p,
471 int entry_fd, uint64_t n_entries,
472 int entry_array_fd, uint64_t n_entry_arrays) {
474 uint64_t i, n, a, last, q;
479 assert(entry_fd >= 0);
480 assert(entry_array_fd >= 0);
482 n = le64toh(o->data.n_entries);
483 a = le64toh(o->data.entry_array_offset);
485 /* Entry array means at least two objects */
487 log_error("Entry array present (entry_array_offset=%"PRIu64", but n_entries=%"PRIu64,
495 /* We already checked that earlier */
496 assert(o->data.entry_offset);
498 last = q = le64toh(o->data.entry_offset);
499 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
508 log_error("Array chain too short at %"PRIu64, p);
512 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
513 log_error("Invalid array at %"PRIu64, p);
517 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
521 next = le64toh(o->entry_array.next_entry_array_offset);
522 if (next != 0 && next <= a) {
523 log_error("Array chain has cycle at %"PRIu64, p);
527 m = journal_file_entry_array_n_items(o);
528 for (j = 0; i < n && j < m; i++, j++) {
530 q = le64toh(o->entry_array.items[j]);
532 log_error("Data object's entry array not sorted at %"PRIu64, p);
537 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
541 /* Pointer might have moved, reposition */
542 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
553 static int verify_hash_table(
555 int data_fd, uint64_t n_data,
556 int entry_fd, uint64_t n_entries,
557 int entry_array_fd, uint64_t n_entry_arrays,
559 bool show_progress) {
565 assert(data_fd >= 0);
566 assert(entry_fd >= 0);
567 assert(entry_array_fd >= 0);
570 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
571 for (i = 0; i < n; i++) {
572 uint64_t last = 0, p;
575 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
577 p = le64toh(f->data_hash_table[i].head_hash_offset);
582 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
583 log_error("Invalid data object at hash entry %"PRIu64" of %"PRIu64,
588 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
592 next = le64toh(o->data.next_hash_offset);
593 if (next != 0 && next <= p) {
594 log_error("Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
599 if (le64toh(o->data.hash) % n != i) {
600 log_error("Hash value mismatch in hash entry %"PRIu64" of %"PRIu64,
605 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
613 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
614 log_error("Tail hash pointer mismatch in hash table");
622 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
627 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
630 q = le64toh(f->data_hash_table[h].head_hash_offset);
637 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
641 q = le64toh(o->data.next_hash_offset);
647 static int verify_entry(
649 Object *o, uint64_t p,
650 int data_fd, uint64_t n_data) {
657 assert(data_fd >= 0);
659 n = journal_file_entry_n_items(o);
660 for (i = 0; i < n; i++) {
664 q = le64toh(o->entry.items[i].object_offset);
665 h = le64toh(o->entry.items[i].hash);
667 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
668 log_error("Invalid data object at entry %"PRIu64, p);
672 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
676 if (le64toh(u->data.hash) != h) {
677 log_error("Hash mismatch for data object at entry %"PRIu64, p);
681 r = data_object_in_hash_table(f, h, q);
685 log_error("Data object missing from hash at entry %"PRIu64, p);
693 static int verify_entry_array(
695 int data_fd, uint64_t n_data,
696 int entry_fd, uint64_t n_entries,
697 int entry_array_fd, uint64_t n_entry_arrays,
699 bool show_progress) {
701 uint64_t i = 0, a, n, last = 0;
705 assert(data_fd >= 0);
706 assert(entry_fd >= 0);
707 assert(entry_array_fd >= 0);
710 n = le64toh(f->header->n_entries);
711 a = le64toh(f->header->entry_array_offset);
717 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
720 log_error("Array chain too short at %"PRIu64" of %"PRIu64, i, n);
724 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
725 log_error("Invalid array at %"PRIu64" of %"PRIu64, i, n);
729 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
733 next = le64toh(o->entry_array.next_entry_array_offset);
734 if (next != 0 && next <= a) {
735 log_error("Array chain has cycle at %"PRIu64" of %"PRIu64, i, n);
739 m = journal_file_entry_array_n_items(o);
740 for (j = 0; i < n && j < m; i++, j++) {
743 p = le64toh(o->entry_array.items[j]);
745 log_error("Entry array not sorted at %"PRIu64" of %"PRIu64,
751 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
752 log_error("Invalid array entry at %"PRIu64" of %"PRIu64,
757 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
761 r = verify_entry(f, o, p, data_fd, n_data);
765 /* Pointer might have moved, reposition */
766 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
777 int journal_file_verify(
780 usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
781 bool show_progress) {
784 uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
786 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
787 sd_id128_t entry_boot_id;
788 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
789 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;
790 usec_t last_usec = 0;
791 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
792 char data_path[] = "/var/tmp/journal-data-XXXXXX",
793 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
794 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
798 uint64_t last_tag = 0;
804 r = journal_file_parse_verification_key(f, key);
806 log_error("Failed to parse seed.");
815 data_fd = mkostemp(data_path, O_CLOEXEC);
817 log_error("Failed to create data file: %m");
823 entry_fd = mkostemp(entry_path, O_CLOEXEC);
825 log_error("Failed to create entry file: %m");
831 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
832 if (entry_array_fd < 0) {
833 log_error("Failed to create entry array file: %m");
837 unlink(entry_array_path);
840 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
842 if (f->header->compatible_flags != 0)
845 log_error("Cannot verify file with unknown extensions.");
850 for (i = 0; i < sizeof(f->header->reserved); i++)
851 if (f->header->reserved[i] != 0) {
852 log_error("Reserved field in non-zero.");
857 /* First iteration: we go through all objects, verify the
858 * superficial structure, headers, hashes. */
860 p = le64toh(f->header->header_size);
863 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
865 r = journal_file_move_to_object(f, -1, p, &o);
867 log_error("Invalid object at "OFSfmt, p);
871 if (p > le64toh(f->header->tail_object_offset)) {
872 log_error("Invalid tail object pointer");
877 if (p == le64toh(f->header->tail_object_offset))
882 r = journal_file_object_verify(f, p, o);
884 log_error("Invalid object contents at "OFSfmt": %s", p, strerror(-r));
888 if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
889 log_error("Compressed object in file without compression at "OFSfmt, p);
894 switch (o->object.type) {
897 r = write_uint64(data_fd, p);
909 if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
910 log_error("First entry before first tag at "OFSfmt, p);
915 r = write_uint64(entry_fd, p);
919 if (le64toh(o->entry.realtime) < last_tag_realtime) {
920 log_error("Older entry after newer tag at "OFSfmt, p);
925 if (!entry_seqnum_set &&
926 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
927 log_error("Head entry sequence number incorrect at "OFSfmt, p);
932 if (entry_seqnum_set &&
933 entry_seqnum >= le64toh(o->entry.seqnum)) {
934 log_error("Entry sequence number out of synchronization at "OFSfmt, p);
939 entry_seqnum = le64toh(o->entry.seqnum);
940 entry_seqnum_set = true;
942 if (entry_monotonic_set &&
943 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
944 entry_monotonic > le64toh(o->entry.monotonic)) {
945 log_error("Entry timestamp out of synchronization at "OFSfmt, p);
950 entry_monotonic = le64toh(o->entry.monotonic);
951 entry_boot_id = o->entry.boot_id;
952 entry_monotonic_set = true;
954 if (!entry_realtime_set &&
955 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
956 log_error("Head entry realtime timestamp incorrect");
961 entry_realtime = le64toh(o->entry.realtime);
962 entry_realtime_set = true;
967 case OBJECT_DATA_HASH_TABLE:
968 if (n_data_hash_tables > 1) {
969 log_error("More than one data hash table at "OFSfmt, p);
974 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
975 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
976 log_error("Header fields for data hash table invalid");
981 n_data_hash_tables++;
984 case OBJECT_FIELD_HASH_TABLE:
985 if (n_field_hash_tables > 1) {
986 log_error("More than one field hash table at "OFSfmt, p);
991 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
992 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
993 log_error("Header fields for field hash table invalid");
998 n_field_hash_tables++;
1001 case OBJECT_ENTRY_ARRAY:
1002 r = write_uint64(entry_array_fd, p);
1006 if (p == le64toh(f->header->entry_array_offset)) {
1007 if (found_main_entry_array) {
1008 log_error("More than one main entry array at "OFSfmt, p);
1013 found_main_entry_array = true;
1020 if (!JOURNAL_HEADER_SEALED(f->header)) {
1021 log_error("Tag object in file without sealing at "OFSfmt, p);
1026 if (le64toh(o->tag.seqnum) != n_tags + 1) {
1027 log_error("Tag sequence number out of synchronization at "OFSfmt, p);
1032 if (le64toh(o->tag.epoch) < last_epoch) {
1033 log_error("Epoch sequence out of synchronization at "OFSfmt, p);
1042 log_debug("Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
1044 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
1045 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
1046 log_error("Tag/entry realtime timestamp out of synchronization at "OFSfmt, p);
1051 /* OK, now we know the epoch. So let's now set
1052 * it, and calculate the HMAC for everything
1053 * since the last tag. */
1054 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
1058 r = journal_file_hmac_start(f);
1062 if (last_tag == 0) {
1063 r = journal_file_hmac_put_header(f);
1067 q = le64toh(f->header->header_size);
1072 r = journal_file_move_to_object(f, -1, q, &o);
1076 r = journal_file_hmac_put_object(f, -1, o, q);
1080 q = q + ALIGN64(le64toh(o->object.size));
1083 /* Position might have changed, let's reposition things */
1084 r = journal_file_move_to_object(f, -1, p, &o);
1088 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1089 log_error("Tag failed verification at "OFSfmt, p);
1094 f->hmac_running = false;
1095 last_tag_realtime = rt;
1096 last_sealed_realtime = entry_realtime;
1099 last_tag = p + ALIGN64(le64toh(o->object.size));
1102 last_epoch = le64toh(o->tag.epoch);
1111 if (p == le64toh(f->header->tail_object_offset))
1114 p = p + ALIGN64(le64toh(o->object.size));
1118 log_error("Tail object pointer dead");
1123 if (n_objects != le64toh(f->header->n_objects)) {
1124 log_error("Object number mismatch");
1129 if (n_entries != le64toh(f->header->n_entries)) {
1130 log_error("Entry number mismatch");
1135 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1136 n_data != le64toh(f->header->n_data)) {
1137 log_error("Data number mismatch");
1142 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1143 n_fields != le64toh(f->header->n_fields)) {
1144 log_error("Field number mismatch");
1149 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1150 n_tags != le64toh(f->header->n_tags)) {
1151 log_error("Tag number mismatch");
1156 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1157 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1158 log_error("Entry array number mismatch");
1163 if (n_data_hash_tables != 1) {
1164 log_error("Missing data hash table");
1169 if (n_field_hash_tables != 1) {
1170 log_error("Missing field hash table");
1175 if (!found_main_entry_array) {
1176 log_error("Missing entry array");
1181 if (entry_seqnum_set &&
1182 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1183 log_error("Invalid tail seqnum");
1188 if (entry_monotonic_set &&
1189 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1190 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1191 log_error("Invalid tail monotonic timestamp");
1196 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1197 log_error("Invalid tail realtime timestamp");
1202 /* Second iteration: we follow all objects referenced from the
1203 * two entry points: the object hash table and the entry
1204 * array. We also check that everything referenced (directly
1205 * or indirectly) in the data hash table also exists in the
1206 * entry array, and vice versa. Note that we do not care for
1207 * unreferenced objects. We only care that everything that is
1208 * referenced is consistent. */
1210 r = verify_entry_array(f,
1212 entry_fd, n_entries,
1213 entry_array_fd, n_entry_arrays,
1219 r = verify_hash_table(f,
1221 entry_fd, n_entries,
1222 entry_array_fd, n_entry_arrays,
1231 mmap_cache_close_fd(f->mmap, data_fd);
1232 mmap_cache_close_fd(f->mmap, entry_fd);
1233 mmap_cache_close_fd(f->mmap, entry_array_fd);
1235 close_nointr_nofail(data_fd);
1236 close_nointr_nofail(entry_fd);
1237 close_nointr_nofail(entry_array_fd);
1239 if (first_contained)
1240 *first_contained = le64toh(f->header->head_entry_realtime);
1242 *last_validated = last_sealed_realtime;
1244 *last_contained = le64toh(f->header->tail_entry_realtime);
1252 log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
1255 (unsigned long long) f->last_stat.st_size,
1256 100 * p / f->last_stat.st_size);
1259 mmap_cache_close_fd(f->mmap, data_fd);
1260 close_nointr_nofail(data_fd);
1263 if (entry_fd >= 0) {
1264 mmap_cache_close_fd(f->mmap, entry_fd);
1265 close_nointr_nofail(entry_fd);
1268 if (entry_array_fd >= 0) {
1269 mmap_cache_close_fd(f->mmap, entry_array_fd);
1270 close_nointr_nofail(entry_array_fd);