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_XZ) &&
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_XZ) {
77 _cleanup_free_ void *b = NULL;
78 uint64_t alloc = 0, b_size;
80 if (!decompress_blob_xz(o->data.payload,
81 le64toh(o->object.size) - offsetof(Object, data.payload),
82 &b, &alloc, &b_size, 0)) {
83 log_error(OFSfmt": XZ decompression failed", offset);
87 h2 = hash64(b, b_size);
89 log_error("XZ compression is not supported");
90 return -EPROTONOSUPPORT;
92 } else if (o->object.flags & OBJECT_COMPRESSED_LZ4) {
94 _cleanup_free_ void *b = NULL;
95 uint64_t alloc = 0, b_size;
97 if (!decompress_blob_xz(o->data.payload,
98 le64toh(o->object.size) - offsetof(Object, data.payload),
99 &b, &alloc, &b_size, 0)) {
100 log_error(OFSfmt": LZ4 decompression failed", offset);
104 h2 = hash64(b, b_size);
106 log_error("XZ compression is not supported");
107 return -EPROTONOSUPPORT;
110 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
113 log_error(OFSfmt": invalid hash (%08"PRIx64" vs. %08"PRIx64, offset, h1, h2);
117 if (!VALID64(o->data.next_hash_offset) ||
118 !VALID64(o->data.next_field_offset) ||
119 !VALID64(o->data.entry_offset) ||
120 !VALID64(o->data.entry_array_offset)) {
121 log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
123 o->data.next_hash_offset,
124 o->data.next_field_offset,
125 o->data.entry_offset,
126 o->data.entry_array_offset);
134 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
135 log_error(OFSfmt": bad field size (<= %zu): %"PRIu64,
137 offsetof(FieldObject, payload),
138 le64toh(o->object.size));
142 if (!VALID64(o->field.next_hash_offset) ||
143 !VALID64(o->field.head_data_offset)) {
144 log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
146 o->field.next_hash_offset,
147 o->field.head_data_offset);
153 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
154 log_error(OFSfmt": bad entry size (<= %zu): %"PRIu64,
156 offsetof(EntryObject, items),
157 le64toh(o->object.size));
161 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
162 log_error(OFSfmt": invalid number items in entry: %"PRIu64,
164 (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
168 if (le64toh(o->entry.seqnum) <= 0) {
169 log_error(OFSfmt": invalid entry seqnum: %"PRIx64,
171 le64toh(o->entry.seqnum));
175 if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
176 log_error(OFSfmt": invalid entry realtime timestamp: %"PRIu64,
178 le64toh(o->entry.realtime));
182 if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
183 log_error(OFSfmt": invalid entry monotonic timestamp: %"PRIu64,
185 le64toh(o->entry.monotonic));
189 for (i = 0; i < journal_file_entry_n_items(o); i++) {
190 if (o->entry.items[i].object_offset == 0 ||
191 !VALID64(o->entry.items[i].object_offset)) {
192 log_error(OFSfmt": invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
194 i, journal_file_entry_n_items(o),
195 o->entry.items[i].object_offset);
202 case OBJECT_DATA_HASH_TABLE:
203 case OBJECT_FIELD_HASH_TABLE:
204 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
205 (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
206 log_error(OFSfmt": invalid %s hash table size: %"PRIu64,
208 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
209 le64toh(o->object.size));
213 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
214 if (o->hash_table.items[i].head_hash_offset != 0 &&
215 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
216 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
218 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
219 i, journal_file_hash_table_n_items(o),
220 le64toh(o->hash_table.items[i].head_hash_offset));
223 if (o->hash_table.items[i].tail_hash_offset != 0 &&
224 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
225 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
227 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
228 i, journal_file_hash_table_n_items(o),
229 le64toh(o->hash_table.items[i].tail_hash_offset));
233 if ((o->hash_table.items[i].head_hash_offset != 0) !=
234 (o->hash_table.items[i].tail_hash_offset != 0)) {
235 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
237 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
238 i, journal_file_hash_table_n_items(o),
239 le64toh(o->hash_table.items[i].head_hash_offset),
240 le64toh(o->hash_table.items[i].tail_hash_offset));
247 case OBJECT_ENTRY_ARRAY:
248 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
249 (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
250 log_error(OFSfmt": invalid object entry array size: %"PRIu64,
252 le64toh(o->object.size));
256 if (!VALID64(o->entry_array.next_entry_array_offset)) {
257 log_error(OFSfmt": invalid object entry array next_entry_array_offset: "OFSfmt,
259 o->entry_array.next_entry_array_offset);
263 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
264 if (le64toh(o->entry_array.items[i]) != 0 &&
265 !VALID64(le64toh(o->entry_array.items[i]))) {
266 log_error(OFSfmt": invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
268 i, journal_file_entry_array_n_items(o),
269 le64toh(o->entry_array.items[i]));
276 if (le64toh(o->object.size) != sizeof(TagObject)) {
277 log_error(OFSfmt": invalid object tag size: %"PRIu64,
279 le64toh(o->object.size));
283 if (!VALID_EPOCH(o->tag.epoch)) {
284 log_error(OFSfmt": invalid object tag epoch: %"PRIu64,
296 static void draw_progress(uint64_t p, usec_t *last_usec) {
303 z = now(CLOCK_MONOTONIC);
306 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
311 n = (3 * columns()) / 4;
312 j = (n * (unsigned) p) / 65535ULL;
315 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
317 for (i = 0; i < j; i++)
318 fputs("\xe2\x96\x88", stdout);
320 fputs(ANSI_HIGHLIGHT_OFF, stdout);
322 for (i = 0; i < k; i++)
323 fputs("\xe2\x96\x91", stdout);
325 printf(" %3"PRIu64"%%", 100U * p / 65535U);
327 fputs("\r\x1B[?25h", stdout);
331 static void flush_progress(void) {
337 n = (3 * columns()) / 4;
341 for (i = 0; i < n + 5; i++)
348 static int write_uint64(int fd, uint64_t p) {
351 k = write(fd, &p, sizeof(p));
360 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
375 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
394 static int entry_points_to_data(
407 assert(entry_fd >= 0);
409 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
410 log_error("Data object references invalid entry at %"PRIu64, data_p);
414 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
418 n = journal_file_entry_n_items(o);
419 for (i = 0; i < n; i++)
420 if (le64toh(o->entry.items[i].object_offset) == data_p) {
426 log_error("Data object not referenced by linked entry at %"PRIu64, data_p);
430 /* Check if this entry is also in main entry array. Since the
431 * main entry array has already been verified we can rely on
435 n = le64toh(f->header->n_entries);
436 a = le64toh(f->header->entry_array_offset);
441 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
445 m = journal_file_entry_array_n_items(o);
448 if (entry_p <= le64toh(o->entry_array.items[u-1])) {
457 if (le64toh(o->entry_array.items[z]) == entry_p)
463 if (entry_p < le64toh(o->entry_array.items[z]))
469 log_error("Entry object doesn't exist in main entry array at %"PRIu64, entry_p);
474 a = le64toh(o->entry_array.next_entry_array_offset);
480 static int verify_data(
482 Object *o, uint64_t p,
483 int entry_fd, uint64_t n_entries,
484 int entry_array_fd, uint64_t n_entry_arrays) {
486 uint64_t i, n, a, last, q;
491 assert(entry_fd >= 0);
492 assert(entry_array_fd >= 0);
494 n = le64toh(o->data.n_entries);
495 a = le64toh(o->data.entry_array_offset);
497 /* Entry array means at least two objects */
499 log_error("Entry array present (entry_array_offset=%"PRIu64", but n_entries=%"PRIu64,
507 /* We already checked that earlier */
508 assert(o->data.entry_offset);
510 last = q = le64toh(o->data.entry_offset);
511 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
520 log_error("Array chain too short at %"PRIu64, p);
524 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
525 log_error("Invalid array at %"PRIu64, p);
529 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
533 next = le64toh(o->entry_array.next_entry_array_offset);
534 if (next != 0 && next <= a) {
535 log_error("Array chain has cycle at %"PRIu64, p);
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 log_error("Data object's entry array not sorted at %"PRIu64, p);
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 log_error("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 log_error("Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
611 if (le64toh(o->data.hash) % n != i) {
612 log_error("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 log_error("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 log_error("Invalid data object at entry %"PRIu64, p);
684 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
688 if (le64toh(u->data.hash) != h) {
689 log_error("Hash mismatch for data object at entry %"PRIu64, p);
693 r = data_object_in_hash_table(f, h, q);
697 log_error("Data object missing from hash at entry %"PRIu64, p);
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 log_error("Array chain too short at %"PRIu64" of %"PRIu64, i, n);
736 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
737 log_error("Invalid array at %"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) {
747 log_error("Array chain has cycle at %"PRIu64" of %"PRIu64, i, n);
751 m = journal_file_entry_array_n_items(o);
752 for (j = 0; i < n && j < m; i++, j++) {
755 p = le64toh(o->entry_array.items[j]);
757 log_error("Entry array not sorted at %"PRIu64" of %"PRIu64,
763 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
764 log_error("Invalid array entry at %"PRIu64" of %"PRIu64,
769 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
773 r = verify_entry(f, o, p, data_fd, n_data);
777 /* Pointer might have moved, reposition */
778 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
789 int journal_file_verify(
792 usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
793 bool show_progress) {
796 uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
798 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
799 sd_id128_t entry_boot_id;
800 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
801 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;
802 usec_t last_usec = 0;
803 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
807 uint64_t last_tag = 0;
813 r = journal_file_parse_verification_key(f, key);
815 log_error("Failed to parse seed.");
824 data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
826 log_error("Failed to create data file: %m");
831 entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
833 log_error("Failed to create entry file: %m");
838 entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
839 if (entry_array_fd < 0) {
840 log_error("Failed to create entry array file: %m");
846 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
848 if (f->header->compatible_flags != 0)
851 log_error("Cannot verify file with unknown extensions.");
856 for (i = 0; i < sizeof(f->header->reserved); i++)
857 if (f->header->reserved[i] != 0) {
858 log_error("Reserved field in non-zero.");
863 /* First iteration: we go through all objects, verify the
864 * superficial structure, headers, hashes. */
866 p = le64toh(f->header->header_size);
869 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
871 r = journal_file_move_to_object(f, -1, p, &o);
873 log_error("Invalid object at "OFSfmt, p);
877 if (p > le64toh(f->header->tail_object_offset)) {
878 log_error("Invalid tail object pointer");
883 if (p == le64toh(f->header->tail_object_offset))
888 r = journal_file_object_verify(f, p, o);
890 log_error("Invalid object contents at "OFSfmt": %s", p, strerror(-r));
894 if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
895 (o->object.flags & OBJECT_COMPRESSED_LZ4)) {
896 log_error("Objected with double compression at "OFSfmt, p);
901 if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) {
902 log_error("XZ compressed object in file without XZ compression at "OFSfmt, p);
907 if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) {
908 log_error("LZ4 compressed object in file without LZ4 compression at "OFSfmt, p);
913 switch (o->object.type) {
916 r = write_uint64(data_fd, p);
928 if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
929 log_error("First entry before first tag at "OFSfmt, p);
934 r = write_uint64(entry_fd, p);
938 if (le64toh(o->entry.realtime) < last_tag_realtime) {
939 log_error("Older entry after newer tag at "OFSfmt, p);
944 if (!entry_seqnum_set &&
945 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
946 log_error("Head entry sequence number incorrect at "OFSfmt, p);
951 if (entry_seqnum_set &&
952 entry_seqnum >= le64toh(o->entry.seqnum)) {
953 log_error("Entry sequence number out of synchronization at "OFSfmt, p);
958 entry_seqnum = le64toh(o->entry.seqnum);
959 entry_seqnum_set = true;
961 if (entry_monotonic_set &&
962 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
963 entry_monotonic > le64toh(o->entry.monotonic)) {
964 log_error("Entry timestamp out of synchronization at "OFSfmt, p);
969 entry_monotonic = le64toh(o->entry.monotonic);
970 entry_boot_id = o->entry.boot_id;
971 entry_monotonic_set = true;
973 if (!entry_realtime_set &&
974 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
975 log_error("Head entry realtime timestamp incorrect");
980 entry_realtime = le64toh(o->entry.realtime);
981 entry_realtime_set = true;
986 case OBJECT_DATA_HASH_TABLE:
987 if (n_data_hash_tables > 1) {
988 log_error("More than one data hash table at "OFSfmt, p);
993 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
994 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
995 log_error("Header fields for data hash table invalid");
1000 n_data_hash_tables++;
1003 case OBJECT_FIELD_HASH_TABLE:
1004 if (n_field_hash_tables > 1) {
1005 log_error("More than one field hash table at "OFSfmt, p);
1010 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
1011 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
1012 log_error("Header fields for field hash table invalid");
1017 n_field_hash_tables++;
1020 case OBJECT_ENTRY_ARRAY:
1021 r = write_uint64(entry_array_fd, p);
1025 if (p == le64toh(f->header->entry_array_offset)) {
1026 if (found_main_entry_array) {
1027 log_error("More than one main entry array at "OFSfmt, p);
1032 found_main_entry_array = true;
1039 if (!JOURNAL_HEADER_SEALED(f->header)) {
1040 log_error("Tag object in file without sealing at "OFSfmt, p);
1045 if (le64toh(o->tag.seqnum) != n_tags + 1) {
1046 log_error("Tag sequence number out of synchronization at "OFSfmt, p);
1051 if (le64toh(o->tag.epoch) < last_epoch) {
1052 log_error("Epoch sequence out of synchronization at "OFSfmt, p);
1061 log_debug("Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
1063 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
1064 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
1065 log_error("Tag/entry realtime timestamp out of synchronization at "OFSfmt, p);
1070 /* OK, now we know the epoch. So let's now set
1071 * it, and calculate the HMAC for everything
1072 * since the last tag. */
1073 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
1077 r = journal_file_hmac_start(f);
1081 if (last_tag == 0) {
1082 r = journal_file_hmac_put_header(f);
1086 q = le64toh(f->header->header_size);
1091 r = journal_file_move_to_object(f, -1, q, &o);
1095 r = journal_file_hmac_put_object(f, -1, o, q);
1099 q = q + ALIGN64(le64toh(o->object.size));
1102 /* Position might have changed, let's reposition things */
1103 r = journal_file_move_to_object(f, -1, p, &o);
1107 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1108 log_error("Tag failed verification at "OFSfmt, p);
1113 f->hmac_running = false;
1114 last_tag_realtime = rt;
1115 last_sealed_realtime = entry_realtime;
1118 last_tag = p + ALIGN64(le64toh(o->object.size));
1121 last_epoch = le64toh(o->tag.epoch);
1130 if (p == le64toh(f->header->tail_object_offset))
1133 p = p + ALIGN64(le64toh(o->object.size));
1137 log_error("Tail object pointer dead");
1142 if (n_objects != le64toh(f->header->n_objects)) {
1143 log_error("Object number mismatch");
1148 if (n_entries != le64toh(f->header->n_entries)) {
1149 log_error("Entry number mismatch");
1154 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1155 n_data != le64toh(f->header->n_data)) {
1156 log_error("Data number mismatch");
1161 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1162 n_fields != le64toh(f->header->n_fields)) {
1163 log_error("Field number mismatch");
1168 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1169 n_tags != le64toh(f->header->n_tags)) {
1170 log_error("Tag number mismatch");
1175 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1176 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1177 log_error("Entry array number mismatch");
1182 if (n_data_hash_tables != 1) {
1183 log_error("Missing data hash table");
1188 if (n_field_hash_tables != 1) {
1189 log_error("Missing field hash table");
1194 if (!found_main_entry_array) {
1195 log_error("Missing entry array");
1200 if (entry_seqnum_set &&
1201 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1202 log_error("Invalid tail seqnum");
1207 if (entry_monotonic_set &&
1208 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1209 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1210 log_error("Invalid tail monotonic timestamp");
1215 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1216 log_error("Invalid tail realtime timestamp");
1221 /* Second iteration: we follow all objects referenced from the
1222 * two entry points: the object hash table and the entry
1223 * array. We also check that everything referenced (directly
1224 * or indirectly) in the data hash table also exists in the
1225 * entry array, and vice versa. Note that we do not care for
1226 * unreferenced objects. We only care that everything that is
1227 * referenced is consistent. */
1229 r = verify_entry_array(f,
1231 entry_fd, n_entries,
1232 entry_array_fd, n_entry_arrays,
1238 r = verify_hash_table(f,
1240 entry_fd, n_entries,
1241 entry_array_fd, n_entry_arrays,
1250 mmap_cache_close_fd(f->mmap, data_fd);
1251 mmap_cache_close_fd(f->mmap, entry_fd);
1252 mmap_cache_close_fd(f->mmap, entry_array_fd);
1254 safe_close(data_fd);
1255 safe_close(entry_fd);
1256 safe_close(entry_array_fd);
1258 if (first_contained)
1259 *first_contained = le64toh(f->header->head_entry_realtime);
1261 *last_validated = last_sealed_realtime;
1263 *last_contained = le64toh(f->header->tail_entry_realtime);
1271 log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
1274 (unsigned long long) f->last_stat.st_size,
1275 100 * p / f->last_stat.st_size);
1278 mmap_cache_close_fd(f->mmap, data_fd);
1279 safe_close(data_fd);
1282 if (entry_fd >= 0) {
1283 mmap_cache_close_fd(f->mmap, entry_fd);
1284 safe_close(entry_fd);
1287 if (entry_array_fd >= 0) {
1288 mmap_cache_close_fd(f->mmap, entry_array_fd);
1289 safe_close(entry_array_fd);