journal-verify.c revision e627440b41bb0284e4892f7aa9d84c77972487e2
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt This file is part of systemd.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Copyright 2012 Lennart Poettering
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is free software; you can redistribute it and/or modify it
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt under the terms of the GNU Lesser General Public License as published by
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt the Free Software Foundation; either version 2.1 of the License, or
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (at your option) any later version.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is distributed in the hope that it will be useful, but
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WITHOUT ANY WARRANTY; without even the implied warranty of
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Lesser General Public License for more details.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt You should have received a copy of the GNU Lesser General Public License
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt along with systemd; If not, see <http://www.gnu.org/licenses/>.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * - write bit mucking test
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen * - tag timestamps should be between entry timestamps
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen * - output validated time ranges
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen * - add missing fields to journal header dump
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * - Allow building without libgcrypt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * - check with sparse
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * - 64bit conversions
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic int journal_file_object_verify(JournalFile *f, Object *o) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt /* This does various superficial tests about the length an
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt * possible field values. It does not follow any references to
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt * other objects. */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt le64toh(o->object.size) - offsetof(Object, data.payload),
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (le64toh(o->object.size) != sizeof(TagObject))
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic void draw_progress(uint64_t p, usec_t *last_usec) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt unsigned n, i, j, k;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt j = (n * (unsigned) p) / 65535ULL;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt for (i = 0; i < j; i++)
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt for (i = 0; i < k; i++)
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic void flush_progress(void) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt unsigned n, i;
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt for (i = 0; i < n + 5; i++)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (k != sizeof(p))
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flyktstatic int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* Bisection ... */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt a = 0; b = n;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt while (a < b) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt c = (a + b) / 2;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt if (*z == p)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt bool found = false;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt for (i = 0; i < n; i++)
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (le64toh(o->entry.items[i].object_offset) == data_p) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt /* Check if this entry is also in main entry array. Since the
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt * main entry array has already been verified we can rely on
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt * its consistency.*/
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt while (i < n) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt for (j = 0; i < n && j < m; i++, j++)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (le64toh(o->entry_array.items[j]) == entry_p)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt a = le64toh(o->entry_array.next_entry_array_offset);;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt /* We already checked this earlier */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = entry_points_to_data(f, entry_fd, n_entries, q, p);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt while (i < n) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (a == 0) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_error("Array chain too short at %llu.", (unsigned long long) p);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_error("Invalid array at %llu.", (unsigned long long) p);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt next = le64toh(o->entry_array.next_entry_array_offset);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_error("Array chain has cycle at %llu.", (unsigned long long) p);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt for (j = 0; i < n && j < m; i++, j++) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_error("Data object's entry array not sorted at %llu.", (unsigned long long) p);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = entry_points_to_data(f, entry_fd, n_entries, q, p);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* Pointer might have moved, reposition */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
513a6fa8679510ea1b55967bdb482dd5f8a39f21Ronny Chevalier for (i = 0; i < n; i++) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt p = le64toh(f->data_hash_table[i].head_hash_offset);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt while (p != 0) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error("Invalid data object at hash entry %llu of %llu.",
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt (unsigned long long) i, (unsigned long long) n);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error("Hash chain has a cycle in hash entry %llu of %llu.",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt (unsigned long long) i, (unsigned long long) n);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt log_error("Hash value mismatch in hash entry %llu of %llu.",
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt (unsigned long long) i, (unsigned long long) n);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_error("Tail hash pointer mismatch in hash table.");
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flyktstatic int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt q = le64toh(f->data_hash_table[h].head_hash_offset);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt while (q != 0) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt for (i = 0; i < n; i++) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error("Invalid data object at entry %llu.",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt (unsigned long long) o);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error("Hash mismatch for data object at entry %llu.",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt (unsigned long long) p);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r == 0) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error("Data object missing from hash at entry %llu.",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt (unsigned long long) p);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt while (i < n) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (a == 0) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Array chain too short at %llu of %llu.",
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt (unsigned long long) i, (unsigned long long) n);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
513a6fa8679510ea1b55967bdb482dd5f8a39f21Ronny Chevalier (unsigned long long) i, (unsigned long long) n);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt next = le64toh(o->entry_array.next_entry_array_offset);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Array chain has cycle at %llu of %llu.",
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt (unsigned long long) i, (unsigned long long) n);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt for (j = 0; i < n && j < m; i++, j++) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Entry array not sorted at %llu of %llu.",
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt (unsigned long long) i, (unsigned long long) n);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Invalid array entry at %llu of %llu.",
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt (unsigned long long) i, (unsigned long long) n);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* Pointer might have moved, reposition */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int journal_file_parse_verification_key(JournalFile *f, const char *key) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt const char *k;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt for (c = 0; c < seed_size; c++) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt while (*k == '-')
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (x < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (y < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (*k != '/') {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r != 2) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktint journal_file_verify(JournalFile *f, const char *key) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt 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;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt char data_path[] = "/var/tmp/journal-data-XXXXXX",
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt entry_path[] = "/var/tmp/journal-entry-XXXXXX",
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = journal_file_parse_verification_key(f, key);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_error("Failed to create entry array file: %m");
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* First iteration: we go through all objects, verify the
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * superficial structure, headers, hashes. */
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt while (p != 0) {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt if (r < 0) {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt log_error("Invalid object at %llu", (unsigned long long) p);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (le64toh(f->header->tail_object_offset) < p) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Invalid object contents at %llu", (unsigned long long) p);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt !(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Compressed object without compression at %llu", (unsigned long long) p);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Head entry sequence number incorrect");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt entry_monotonic > le64toh(o->entry.monotonic)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Head entry realtime timestamp incorrect");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("More than one data hash table at %llu", (unsigned long long) p);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Header fields for data hash table invalid.");
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt log_error("More than one field hash table at %llu", (unsigned long long) p);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_error("Header fields for field hash table invalid.");
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (p == le64toh(f->header->entry_array_offset)) {
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt log_error("More than one main entry array at %llu", (unsigned long long) p);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Tag object without sealing at %llu", (unsigned long long) p);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt /* OK, now we know the epoch. So let's now set
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt * it, and calculate the HMAC for everything
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt * since the last tag. */
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt while (q <= p) {
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt /* Position might have changed, let's reposition things */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_error("Tag failed verification at %llu", (unsigned long long) p);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt last_tag = p + ALIGN64(le64toh(o->object.size));
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (p == le64toh(f->header->tail_object_offset))
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (n_objects != le64toh(f->header->n_objects)) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (n_entries != le64toh(f->header->n_entries)) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt /* Second iteration: we follow all objects referenced from the
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * two entry points: the object hash table and the entry
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * array. We also check that everything referenced (directly
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * or indirectly) in the data hash table also exists in the
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * entry array, and vice versa. Note that we do not care for
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * unreferenced objects. We only care that everything that is
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * referenced is consistent. */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (unsigned long long) p,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (unsigned long long) (100 * p / f->last_stat.st_size));