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