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) {
58 if (le64toh(o->data.entry_offset) == 0)
59 log_warning(OFSfmt": unused data (entry_offset==0)", offset);
61 if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
62 log_error(OFSfmt": bad n_entries: %"PRIu64, offset, o->data.n_entries);
66 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
67 log_error(OFSfmt": bad object size (<= %zu): %"PRIu64,
69 offsetof(DataObject, payload),
70 le64toh(o->object.size));
74 h1 = le64toh(o->data.hash);
76 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
78 _cleanup_free_ void *b = NULL;
79 uint64_t alloc = 0, b_size;
81 r = decompress_blob(compression,
83 le64toh(o->object.size) - offsetof(Object, data.payload),
84 &b, &alloc, &b_size, 0);
86 log_error(OFSfmt": %s decompression failed: %s", offset,
87 object_compressed_to_string(compression), strerror(-r));
91 h2 = hash64(b, b_size);
93 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
96 log_error(OFSfmt": invalid hash (%08"PRIx64" vs. %08"PRIx64, offset, h1, h2);
100 if (!VALID64(o->data.next_hash_offset) ||
101 !VALID64(o->data.next_field_offset) ||
102 !VALID64(o->data.entry_offset) ||
103 !VALID64(o->data.entry_array_offset)) {
104 log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
106 o->data.next_hash_offset,
107 o->data.next_field_offset,
108 o->data.entry_offset,
109 o->data.entry_array_offset);
117 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
118 log_error(OFSfmt": bad field size (<= %zu): %"PRIu64,
120 offsetof(FieldObject, payload),
121 le64toh(o->object.size));
125 if (!VALID64(o->field.next_hash_offset) ||
126 !VALID64(o->field.head_data_offset)) {
127 log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
129 o->field.next_hash_offset,
130 o->field.head_data_offset);
136 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
137 log_error(OFSfmt": bad entry size (<= %zu): %"PRIu64,
139 offsetof(EntryObject, items),
140 le64toh(o->object.size));
144 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
145 log_error(OFSfmt": invalid number items in entry: %"PRIu64,
147 (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
151 if (le64toh(o->entry.seqnum) <= 0) {
152 log_error(OFSfmt": invalid entry seqnum: %"PRIx64,
154 le64toh(o->entry.seqnum));
158 if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
159 log_error(OFSfmt": invalid entry realtime timestamp: %"PRIu64,
161 le64toh(o->entry.realtime));
165 if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
166 log_error(OFSfmt": invalid entry monotonic timestamp: %"PRIu64,
168 le64toh(o->entry.monotonic));
172 for (i = 0; i < journal_file_entry_n_items(o); i++) {
173 if (o->entry.items[i].object_offset == 0 ||
174 !VALID64(o->entry.items[i].object_offset)) {
175 log_error(OFSfmt": invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
177 i, journal_file_entry_n_items(o),
178 o->entry.items[i].object_offset);
185 case OBJECT_DATA_HASH_TABLE:
186 case OBJECT_FIELD_HASH_TABLE:
187 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
188 (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
189 log_error(OFSfmt": invalid %s hash table size: %"PRIu64,
191 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
192 le64toh(o->object.size));
196 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
197 if (o->hash_table.items[i].head_hash_offset != 0 &&
198 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
199 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
201 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
202 i, journal_file_hash_table_n_items(o),
203 le64toh(o->hash_table.items[i].head_hash_offset));
206 if (o->hash_table.items[i].tail_hash_offset != 0 &&
207 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
208 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
210 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
211 i, journal_file_hash_table_n_items(o),
212 le64toh(o->hash_table.items[i].tail_hash_offset));
216 if ((o->hash_table.items[i].head_hash_offset != 0) !=
217 (o->hash_table.items[i].tail_hash_offset != 0)) {
218 log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
220 o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
221 i, journal_file_hash_table_n_items(o),
222 le64toh(o->hash_table.items[i].head_hash_offset),
223 le64toh(o->hash_table.items[i].tail_hash_offset));
230 case OBJECT_ENTRY_ARRAY:
231 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
232 (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
233 log_error(OFSfmt": invalid object entry array size: %"PRIu64,
235 le64toh(o->object.size));
239 if (!VALID64(o->entry_array.next_entry_array_offset)) {
240 log_error(OFSfmt": invalid object entry array next_entry_array_offset: "OFSfmt,
242 o->entry_array.next_entry_array_offset);
246 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
247 if (le64toh(o->entry_array.items[i]) != 0 &&
248 !VALID64(le64toh(o->entry_array.items[i]))) {
249 log_error(OFSfmt": invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
251 i, journal_file_entry_array_n_items(o),
252 le64toh(o->entry_array.items[i]));
259 if (le64toh(o->object.size) != sizeof(TagObject)) {
260 log_error(OFSfmt": invalid object tag size: %"PRIu64,
262 le64toh(o->object.size));
266 if (!VALID_EPOCH(o->tag.epoch)) {
267 log_error(OFSfmt": invalid object tag epoch: %"PRIu64,
279 static void draw_progress(uint64_t p, usec_t *last_usec) {
286 z = now(CLOCK_MONOTONIC);
289 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
294 n = (3 * columns()) / 4;
295 j = (n * (unsigned) p) / 65535ULL;
298 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
300 for (i = 0; i < j; i++)
301 fputs("\xe2\x96\x88", stdout);
303 fputs(ANSI_HIGHLIGHT_OFF, stdout);
305 for (i = 0; i < k; i++)
306 fputs("\xe2\x96\x91", stdout);
308 printf(" %3"PRIu64"%%", 100U * p / 65535U);
310 fputs("\r\x1B[?25h", stdout);
314 static void flush_progress(void) {
320 n = (3 * columns()) / 4;
324 for (i = 0; i < n + 5; i++)
331 static int write_uint64(int fd, uint64_t p) {
334 k = write(fd, &p, sizeof(p));
343 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
358 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
377 static int entry_points_to_data(
390 assert(entry_fd >= 0);
392 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
393 log_error("Data object references invalid entry at %"PRIu64, data_p);
397 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
401 n = journal_file_entry_n_items(o);
402 for (i = 0; i < n; i++)
403 if (le64toh(o->entry.items[i].object_offset) == data_p) {
409 log_error("Data object not referenced by linked entry at %"PRIu64, data_p);
413 /* Check if this entry is also in main entry array. Since the
414 * main entry array has already been verified we can rely on
418 n = le64toh(f->header->n_entries);
419 a = le64toh(f->header->entry_array_offset);
424 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
428 m = journal_file_entry_array_n_items(o);
431 if (entry_p <= le64toh(o->entry_array.items[u-1])) {
440 if (le64toh(o->entry_array.items[z]) == entry_p)
446 if (entry_p < le64toh(o->entry_array.items[z]))
452 log_error("Entry object doesn't exist in main entry array at %"PRIu64, entry_p);
457 a = le64toh(o->entry_array.next_entry_array_offset);
463 static int verify_data(
465 Object *o, uint64_t p,
466 int entry_fd, uint64_t n_entries,
467 int entry_array_fd, uint64_t n_entry_arrays) {
469 uint64_t i, n, a, last, q;
474 assert(entry_fd >= 0);
475 assert(entry_array_fd >= 0);
477 n = le64toh(o->data.n_entries);
478 a = le64toh(o->data.entry_array_offset);
480 /* Entry array means at least two objects */
482 log_error("Entry array present (entry_array_offset=%"PRIu64", but n_entries=%"PRIu64,
490 /* We already checked that earlier */
491 assert(o->data.entry_offset);
493 last = q = le64toh(o->data.entry_offset);
494 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
503 log_error("Array chain too short at %"PRIu64, p);
507 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
508 log_error("Invalid array at %"PRIu64, p);
512 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
516 next = le64toh(o->entry_array.next_entry_array_offset);
517 if (next != 0 && next <= a) {
518 log_error("Array chain has cycle at %"PRIu64, p);
522 m = journal_file_entry_array_n_items(o);
523 for (j = 0; i < n && j < m; i++, j++) {
525 q = le64toh(o->entry_array.items[j]);
527 log_error("Data object's entry array not sorted at %"PRIu64, p);
532 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
536 /* Pointer might have moved, reposition */
537 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
548 static int verify_hash_table(
550 int data_fd, uint64_t n_data,
551 int entry_fd, uint64_t n_entries,
552 int entry_array_fd, uint64_t n_entry_arrays,
554 bool show_progress) {
560 assert(data_fd >= 0);
561 assert(entry_fd >= 0);
562 assert(entry_array_fd >= 0);
565 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
566 for (i = 0; i < n; i++) {
567 uint64_t last = 0, p;
570 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
572 p = le64toh(f->data_hash_table[i].head_hash_offset);
577 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
578 log_error("Invalid data object at hash entry %"PRIu64" of %"PRIu64,
583 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
587 next = le64toh(o->data.next_hash_offset);
588 if (next != 0 && next <= p) {
589 log_error("Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
594 if (le64toh(o->data.hash) % n != i) {
595 log_error("Hash value mismatch in hash entry %"PRIu64" of %"PRIu64,
600 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
608 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
609 log_error("Tail hash pointer mismatch in hash table");
617 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
622 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
625 q = le64toh(f->data_hash_table[h].head_hash_offset);
632 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
636 q = le64toh(o->data.next_hash_offset);
642 static int verify_entry(
644 Object *o, uint64_t p,
645 int data_fd, uint64_t n_data) {
652 assert(data_fd >= 0);
654 n = journal_file_entry_n_items(o);
655 for (i = 0; i < n; i++) {
659 q = le64toh(o->entry.items[i].object_offset);
660 h = le64toh(o->entry.items[i].hash);
662 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
663 log_error("Invalid data object at entry %"PRIu64, p);
667 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
671 if (le64toh(u->data.hash) != h) {
672 log_error("Hash mismatch for data object at entry %"PRIu64, p);
676 r = data_object_in_hash_table(f, h, q);
680 log_error("Data object missing from hash at entry %"PRIu64, p);
688 static int verify_entry_array(
690 int data_fd, uint64_t n_data,
691 int entry_fd, uint64_t n_entries,
692 int entry_array_fd, uint64_t n_entry_arrays,
694 bool show_progress) {
696 uint64_t i = 0, a, n, last = 0;
700 assert(data_fd >= 0);
701 assert(entry_fd >= 0);
702 assert(entry_array_fd >= 0);
705 n = le64toh(f->header->n_entries);
706 a = le64toh(f->header->entry_array_offset);
712 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
715 log_error("Array chain too short at %"PRIu64" of %"PRIu64, i, n);
719 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
720 log_error("Invalid array at %"PRIu64" of %"PRIu64, i, n);
724 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
728 next = le64toh(o->entry_array.next_entry_array_offset);
729 if (next != 0 && next <= a) {
730 log_error("Array chain has cycle at %"PRIu64" of %"PRIu64, i, n);
734 m = journal_file_entry_array_n_items(o);
735 for (j = 0; i < n && j < m; i++, j++) {
738 p = le64toh(o->entry_array.items[j]);
740 log_error("Entry array not sorted at %"PRIu64" of %"PRIu64,
746 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
747 log_error("Invalid array entry at %"PRIu64" of %"PRIu64,
752 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
756 r = verify_entry(f, o, p, data_fd, n_data);
760 /* Pointer might have moved, reposition */
761 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
772 int journal_file_verify(
775 usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
776 bool show_progress) {
779 uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
781 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
782 sd_id128_t entry_boot_id;
783 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
784 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;
785 usec_t last_usec = 0;
786 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
790 uint64_t last_tag = 0;
796 r = journal_file_parse_verification_key(f, key);
798 log_error("Failed to parse seed.");
807 data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
809 log_error("Failed to create data file: %m");
814 entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
816 log_error("Failed to create entry file: %m");
821 entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
822 if (entry_array_fd < 0) {
823 log_error("Failed to create entry array file: %m");
829 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
831 if (f->header->compatible_flags != 0)
834 log_error("Cannot verify file with unknown extensions.");
839 for (i = 0; i < sizeof(f->header->reserved); i++)
840 if (f->header->reserved[i] != 0) {
841 log_error("Reserved field in non-zero.");
846 /* First iteration: we go through all objects, verify the
847 * superficial structure, headers, hashes. */
849 p = le64toh(f->header->header_size);
852 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
854 r = journal_file_move_to_object(f, -1, p, &o);
856 log_error("Invalid object at "OFSfmt, p);
860 if (p > le64toh(f->header->tail_object_offset)) {
861 log_error("Invalid tail object pointer");
866 if (p == le64toh(f->header->tail_object_offset))
871 r = journal_file_object_verify(f, p, o);
873 log_error("Invalid object contents at "OFSfmt": %s", p, strerror(-r));
877 if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
878 (o->object.flags & OBJECT_COMPRESSED_LZ4)) {
879 log_error("Objected with double compression at "OFSfmt, p);
884 if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) {
885 log_error("XZ compressed object in file without XZ compression at "OFSfmt, p);
890 if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) {
891 log_error("LZ4 compressed object in file without LZ4 compression at "OFSfmt, p);
896 switch (o->object.type) {
899 r = write_uint64(data_fd, p);
911 if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
912 log_error("First entry before first tag at "OFSfmt, p);
917 r = write_uint64(entry_fd, p);
921 if (le64toh(o->entry.realtime) < last_tag_realtime) {
922 log_error("Older entry after newer tag at "OFSfmt, p);
927 if (!entry_seqnum_set &&
928 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
929 log_error("Head entry sequence number incorrect at "OFSfmt, p);
934 if (entry_seqnum_set &&
935 entry_seqnum >= le64toh(o->entry.seqnum)) {
936 log_error("Entry sequence number out of synchronization at "OFSfmt, p);
941 entry_seqnum = le64toh(o->entry.seqnum);
942 entry_seqnum_set = true;
944 if (entry_monotonic_set &&
945 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
946 entry_monotonic > le64toh(o->entry.monotonic)) {
947 log_error("Entry timestamp out of synchronization at "OFSfmt, p);
952 entry_monotonic = le64toh(o->entry.monotonic);
953 entry_boot_id = o->entry.boot_id;
954 entry_monotonic_set = true;
956 if (!entry_realtime_set &&
957 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
958 log_error("Head entry realtime timestamp incorrect");
963 entry_realtime = le64toh(o->entry.realtime);
964 entry_realtime_set = true;
969 case OBJECT_DATA_HASH_TABLE:
970 if (n_data_hash_tables > 1) {
971 log_error("More than one data hash table at "OFSfmt, p);
976 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
977 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
978 log_error("Header fields for data hash table invalid");
983 n_data_hash_tables++;
986 case OBJECT_FIELD_HASH_TABLE:
987 if (n_field_hash_tables > 1) {
988 log_error("More than one field hash table at "OFSfmt, p);
993 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
994 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
995 log_error("Header fields for field hash table invalid");
1000 n_field_hash_tables++;
1003 case OBJECT_ENTRY_ARRAY:
1004 r = write_uint64(entry_array_fd, p);
1008 if (p == le64toh(f->header->entry_array_offset)) {
1009 if (found_main_entry_array) {
1010 log_error("More than one main entry array at "OFSfmt, p);
1015 found_main_entry_array = true;
1022 if (!JOURNAL_HEADER_SEALED(f->header)) {
1023 log_error("Tag object in file without sealing at "OFSfmt, p);
1028 if (le64toh(o->tag.seqnum) != n_tags + 1) {
1029 log_error("Tag sequence number out of synchronization at "OFSfmt, p);
1034 if (le64toh(o->tag.epoch) < last_epoch) {
1035 log_error("Epoch sequence out of synchronization at "OFSfmt, p);
1044 log_debug("Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
1046 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
1047 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
1048 log_error("Tag/entry realtime timestamp out of synchronization at "OFSfmt, p);
1053 /* OK, now we know the epoch. So let's now set
1054 * it, and calculate the HMAC for everything
1055 * since the last tag. */
1056 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
1060 r = journal_file_hmac_start(f);
1064 if (last_tag == 0) {
1065 r = journal_file_hmac_put_header(f);
1069 q = le64toh(f->header->header_size);
1074 r = journal_file_move_to_object(f, -1, q, &o);
1078 r = journal_file_hmac_put_object(f, -1, o, q);
1082 q = q + ALIGN64(le64toh(o->object.size));
1085 /* Position might have changed, let's reposition things */
1086 r = journal_file_move_to_object(f, -1, p, &o);
1090 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
1091 log_error("Tag failed verification at "OFSfmt, p);
1096 f->hmac_running = false;
1097 last_tag_realtime = rt;
1098 last_sealed_realtime = entry_realtime;
1101 last_tag = p + ALIGN64(le64toh(o->object.size));
1104 last_epoch = le64toh(o->tag.epoch);
1113 if (p == le64toh(f->header->tail_object_offset))
1116 p = p + ALIGN64(le64toh(o->object.size));
1120 log_error("Tail object pointer dead");
1125 if (n_objects != le64toh(f->header->n_objects)) {
1126 log_error("Object number mismatch");
1131 if (n_entries != le64toh(f->header->n_entries)) {
1132 log_error("Entry number mismatch");
1137 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1138 n_data != le64toh(f->header->n_data)) {
1139 log_error("Data number mismatch");
1144 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1145 n_fields != le64toh(f->header->n_fields)) {
1146 log_error("Field number mismatch");
1151 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1152 n_tags != le64toh(f->header->n_tags)) {
1153 log_error("Tag number mismatch");
1158 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1159 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1160 log_error("Entry array number mismatch");
1165 if (n_data_hash_tables != 1) {
1166 log_error("Missing data hash table");
1171 if (n_field_hash_tables != 1) {
1172 log_error("Missing field hash table");
1177 if (!found_main_entry_array) {
1178 log_error("Missing entry array");
1183 if (entry_seqnum_set &&
1184 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1185 log_error("Invalid tail seqnum");
1190 if (entry_monotonic_set &&
1191 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1192 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1193 log_error("Invalid tail monotonic timestamp");
1198 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1199 log_error("Invalid tail realtime timestamp");
1204 /* Second iteration: we follow all objects referenced from the
1205 * two entry points: the object hash table and the entry
1206 * array. We also check that everything referenced (directly
1207 * or indirectly) in the data hash table also exists in the
1208 * entry array, and vice versa. Note that we do not care for
1209 * unreferenced objects. We only care that everything that is
1210 * referenced is consistent. */
1212 r = verify_entry_array(f,
1214 entry_fd, n_entries,
1215 entry_array_fd, n_entry_arrays,
1221 r = verify_hash_table(f,
1223 entry_fd, n_entries,
1224 entry_array_fd, n_entry_arrays,
1233 mmap_cache_close_fd(f->mmap, data_fd);
1234 mmap_cache_close_fd(f->mmap, entry_fd);
1235 mmap_cache_close_fd(f->mmap, entry_array_fd);
1237 safe_close(data_fd);
1238 safe_close(entry_fd);
1239 safe_close(entry_array_fd);
1241 if (first_contained)
1242 *first_contained = le64toh(f->header->head_entry_realtime);
1244 *last_validated = last_sealed_realtime;
1246 *last_contained = le64toh(f->header->tail_entry_realtime);
1254 log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
1257 (unsigned long long) f->last_stat.st_size,
1258 100 * p / f->last_stat.st_size);
1261 mmap_cache_close_fd(f->mmap, data_fd);
1262 safe_close(data_fd);
1265 if (entry_fd >= 0) {
1266 mmap_cache_close_fd(f->mmap, entry_fd);
1267 safe_close(entry_fd);
1270 if (entry_array_fd >= 0) {
1271 mmap_cache_close_fd(f->mmap, entry_array_fd);
1272 safe_close(entry_array_fd);