journal-verify.c revision c0ca7aeec963207b6fa5ee39bd204cb26cba4023
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen This file is part of systemd.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen Copyright 2012 Lennart Poettering
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen systemd is free software; you can redistribute it and/or modify it
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen under the terms of the GNU Lesser General Public License as published by
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen the Free Software Foundation; either version 2.1 of the License, or
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (at your option) any later version.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen systemd is distributed in the hope that it will be useful, but
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen WITHOUT ANY WARRANTY; without even the implied warranty of
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen Lesser General Public License for more details.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen You should have received a copy of the GNU Lesser General Public License
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include "journal-authenticate.h"
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poetteringstatic int journal_file_object_verify(JournalFile *f, Object *o) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* This does various superficial tests about the length an
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * possible field values. It does not follow any references to
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * other objects. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if ((o->object.flags & OBJECT_COMPRESSED) &&
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen o->object.type != OBJECT_DATA)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(o->data.entry_offset) <= 0 ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen le64toh(o->data.n_entries) <= 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (o->object.flags & OBJECT_COMPRESSED) {
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek if (!uncompress_blob(o->data.payload,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen le64toh(o->object.size) - offsetof(Object, data.payload),
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!VALID64(o->data.next_hash_offset) ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen !VALID64(o->data.next_field_offset) ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen !VALID64(o->data.entry_offset) ||
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek !VALID64(o->data.entry_array_offset))
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek if (!VALID64(o->field.next_hash_offset) ||
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek !VALID64(o->field.head_data_offset))
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek if (le64toh(o->entry.seqnum) <= 0 ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen !VALID_REALTIME(le64toh(o->entry.realtime)) ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (i = 0; i < journal_file_entry_n_items(o); i++) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (o->entry.items[i].object_offset == 0 ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen !VALID64(o->entry.items[i].object_offset))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen case OBJECT_FIELD_HASH_TABLE:
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (o->hash_table.items[i].head_hash_offset != 0 &&
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (o->hash_table.items[i].tail_hash_offset != 0 &&
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
b7e7184634d573fb73143210962acce205f37f61Michael Biebl if ((o->hash_table.items[i].head_hash_offset != 0) !=
b7e7184634d573fb73143210962acce205f37f61Michael Biebl (o->hash_table.items[i].tail_hash_offset != 0))
b7e7184634d573fb73143210962acce205f37f61Michael Biebl if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
b7e7184634d573fb73143210962acce205f37f61Michael Biebl if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
b7e7184634d573fb73143210962acce205f37f61Michael Biebl if (!VALID64(o->entry_array.next_entry_array_offset))
b7e7184634d573fb73143210962acce205f37f61Michael Biebl for (i = 0; i < journal_file_entry_array_n_items(o); i++)
8fba1c8d4e3d05d2af2848b6570bdc09e725d06eZbigniew Jędrzejewski-Szmek if (le64toh(o->object.size) != sizeof(TagObject))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!VALID_EPOCH(o->tag.epoch))
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pittstatic void draw_progress(uint64_t p, usec_t *last_usec) {
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt unsigned n, i, j, k;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen j = (n * (unsigned) p) / 65535ULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (i = 0; i < j; i++)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen fputs("\xe2\x96\x88", stdout);
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen fputs(ANSI_HIGHLIGHT_OFF, stdout);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (i = 0; i < k; i++)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen fputs("\xe2\x96\x91", stdout);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen fputs("\r\x1B[?25h", stdout);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenstatic void flush_progress(void) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (i = 0; i < n + 5; i++)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenstatic int write_uint64(int fd, uint64_t p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen k = write(fd, &p, sizeof(p));
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (k != sizeof(p))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenstatic int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
0b2ec8a3bfdd6118b3b4958d236ee203ad420f28David Herrmann /* Bisection ... */
264581a2f1599a27de577549dc75fccefef6a579Felipe Sateler a = 0; b = n;
264581a2f1599a27de577549dc75fccefef6a579Felipe Sateler while (a < b) {
0b2ec8a3bfdd6118b3b4958d236ee203ad420f28David Herrmann c = (a + b) / 2;
0b2ec8a3bfdd6118b3b4958d236ee203ad420f28David Herrmann r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenstatic int entry_points_to_data(
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen n = journal_file_entry_n_items(o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (i = 0; i < n; i++)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(o->entry.items[i].object_offset) == data_p) {
29e0e6d8c1f7f648b7c998880d034eaa3e58c53aMartin Pitt log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
4e4885553447f6f4c014bfa3e5b5837a76a0e612Lennart Poettering /* Check if this entry is also in main entry array. Since the
3315f085178f46155fda345d9526c09083b45946Lennart Poettering * main entry array has already been verified we can rely on
3315f085178f46155fda345d9526c09083b45946Lennart Poettering * its consistency.*/
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen n = le64toh(f->header->n_entries);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen a = le64toh(f->header->entry_array_offset);
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering while (i < n) {
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (entry_p <= le64toh(o->entry_array.items[u-1])) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(o->entry_array.items[z]) == entry_p)
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (entry_p < le64toh(o->entry_array.items[z]))
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek log_error("Entry object doesn't exist in main entry array at %llu", (unsigned long long) entry_p);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek a = le64toh(o->entry_array.next_entry_array_offset);
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek int entry_fd, uint64_t n_entries,
f2341e0a87cab1558c84c933956e9181d5fb6c52Lennart Poettering int entry_array_fd, uint64_t n_entry_arrays) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek n = le64toh(o->data.n_entries);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek a = le64toh(o->data.entry_array_offset);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek /* We already checked this earlier */
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek last = q = le64toh(o->data.entry_offset);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek r = entry_points_to_data(f, entry_fd, n_entries, q, p);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek log_error("Array chain too short at %llu", (unsigned long long) p);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek log_error("Invalid array at %llu", (unsigned long long) p);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek next = le64toh(o->entry_array.next_entry_array_offset);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek log_error("Array chain has cycle at %llu", (unsigned long long) p);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek m = journal_file_entry_array_n_items(o);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek for (j = 0; i < n && j < m; i++, j++) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek q = le64toh(o->entry_array.items[j]);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek r = entry_points_to_data(f, entry_fd, n_entries, q, p);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek /* Pointer might have moved, reposition */
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int data_fd, uint64_t n_data,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int entry_fd, uint64_t n_entries,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int entry_array_fd, uint64_t n_entry_arrays,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt for (i = 0; i < n; i++) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = le64toh(f->data_hash_table[i].head_hash_offset);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Invalid data object at hash entry %llu of %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) i, (unsigned long long) n);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen next = le64toh(o->data.next_hash_offset);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (next != 0 && next <= p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Hash chain has a cycle in hash entry %llu of %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) i, (unsigned long long) n);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(o->data.hash) % n != i) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Hash value mismatch in hash entry %llu of %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) i, (unsigned long long) n);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Tail hash pointer mismatch in hash table");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenstatic int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen q = le64toh(f->data_hash_table[h].head_hash_offset);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen q = le64toh(o->data.next_hash_offset);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int data_fd, uint64_t n_data) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen n = journal_file_entry_n_items(o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (i = 0; i < n; i++) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen q = le64toh(o->entry.items[i].object_offset);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen h = le64toh(o->entry.items[i].hash);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Invalid data object at entry %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(u->data.hash) != h) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Hash mismatch for data object at entry %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = data_object_in_hash_table(f, h, q);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Data object missing from hash at entry %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenstatic int verify_entry_array(
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek int entry_fd, uint64_t n_entries,
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek int entry_array_fd, uint64_t n_entry_arrays,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen uint64_t i = 0, a, n, last = 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen n = le64toh(f->header->n_entries);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen a = le64toh(f->header->entry_array_offset);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Array chain too short at %llu of %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) i, (unsigned long long) n);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Invalid array at %llu of %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) i, (unsigned long long) n);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen next = le64toh(o->entry_array.next_entry_array_offset);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (next != 0 && next <= a) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Array chain has cycle at %llu of %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) i, (unsigned long long) n);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen m = journal_file_entry_array_n_items(o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (j = 0; i < n && j < m; i++, j++) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = le64toh(o->entry_array.items[j]);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Entry array not sorted at %llu of %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) i, (unsigned long long) n);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Invalid array entry at %llu of %llu",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (unsigned long long) i, (unsigned long long) n);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = verify_entry(f, o, p, data_fd, n_data);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Pointer might have moved, reposition */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen 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;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char data_path[] = "/var/tmp/journal-data-XXXXXX",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen entry_path[] = "/var/tmp/journal-entry-XXXXXX",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_parse_verification_key(f, key);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Failed to parse seed.");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen data_fd = mkostemp(data_path, O_CLOEXEC);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Failed to create data file: %m");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen entry_fd = mkostemp(entry_path, O_CLOEXEC);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Failed to create entry file: %m");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Failed to create entry array file: %m");
a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0eZbigniew Jędrzejewski-Szmek if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (f->header->compatible_flags != 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Cannot verify file with unknown extensions.");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (i = 0; i < sizeof(f->header->reserved); i++)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (f->header->reserved[i] != 0) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Reserved field in non-zero.");
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering /* First iteration: we go through all objects, verify the
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering * superficial structure, headers, hashes. */
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering while (p != 0) {
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, -1, p, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Invalid object at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (p > le64toh(f->header->tail_object_offset)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Invalid tail object pointer");
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering if (p == le64toh(f->header->tail_object_offset))
a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0eZbigniew Jędrzejewski-Szmek r = journal_file_object_verify(f, o);
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt if (r < 0) {
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt log_error("Invalid object contents at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = write_uint64(data_fd, p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("First entry before first tag at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = write_uint64(entry_fd, p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(o->entry.realtime) < last_tag_realtime) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Older entry after newer tag at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
7a03974a6f4510dcb1850515a80c2063c767a80fThomas Hindoe Paaboel Andersen entry_seqnum = le64toh(o->entry.seqnum);
a34bf9db5da0fdd6bdb14459e203dbe41ee99614Lennart Poettering sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen entry_monotonic > le64toh(o->entry.monotonic)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen entry_monotonic = le64toh(o->entry.monotonic);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen entry_boot_id = o->entry.boot_id;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Head entry realtime timestamp incorrect");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen entry_realtime = le64toh(o->entry.realtime);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (n_data_hash_tables > 1) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("More than one data hash table at %llu", (unsigned long long) p);
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Header fields for data hash table invalid");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen case OBJECT_FIELD_HASH_TABLE:
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("More than one field hash table at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Header fields for field hash table invalid");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = write_uint64(entry_array_fd, p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (p == le64toh(f->header->entry_array_offset)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (found_main_entry_array) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("More than one main entry array at %llu", (unsigned long long) p);
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen found_main_entry_array = true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!JOURNAL_HEADER_SEALED(f->header)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(o->tag.seqnum) != n_tags + 1) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (le64toh(o->tag.epoch) < last_epoch) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* OK, now we know the epoch. So let's now set
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * it, and calculate the HMAC for everything
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * since the last tag. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_hmac_put_header(f);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen q = le64toh(f->header->header_size);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = journal_file_move_to_object(f, -1, q, &o);
a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0eZbigniew Jędrzejewski-Szmek r = journal_file_hmac_put_object(f, -1, q);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen q = q + ALIGN64(le64toh(o->object.size));
b3fae863ef548add2d01c3956ce7720f4eeeca7eLennart Poettering /* Position might have changed, let's reposition things */
b3fae863ef548add2d01c3956ce7720f4eeeca7eLennart Poettering r = journal_file_move_to_object(f, -1, p, &o);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_error("Tag failed verification at %llu", (unsigned long long) p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen last_sealed_realtime = entry_realtime;
n_tags ++;
n_weird ++;
if (!found_last) {
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
if (!found_main_entry_array) {
r = -EBADMSG;
goto fail;
if (entry_seqnum_set &&
r = -EBADMSG;
goto fail;
if (entry_monotonic_set &&
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = verify_entry_array(f,
goto fail;
r = verify_hash_table(f,
goto fail;
if (show_progress)
if (first_validated)
if (last_validated)
if (last_contained)
fail:
if (show_progress)
f->path,
if (data_fd >= 0) {
if (entry_fd >= 0) {
if (entry_array_fd >= 0) {