journal-verify.c revision 76ef789d264f9eb7d7624b994aa6eead1dacfac4
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/***
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering This file is part of systemd.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Copyright 2012 Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering systemd is free software; you can redistribute it and/or modify it
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering under the terms of the GNU Lesser General Public License as published by
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering (at your option) any later version.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering systemd is distributed in the hope that it will be useful, but
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Lesser General Public License for more details.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering You should have received a copy of the GNU Lesser General Public License
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering***/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <unistd.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <sys/mman.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <fcntl.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <stddef.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "util.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "macro.h"
9eb977db5b89b44f254ab40c1876a76b7d7ea2d0Kay Sievers#include "journal-def.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "journal-file.h"
a5c32cff1f56afe6f0c6c70d91a88a7a8238b2d7Harald Hoyer#include "journal-authenticate.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "journal-verify.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "lookup3.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "compress.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "terminal-util.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic void draw_progress(uint64_t p, usec_t *last_usec) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering unsigned n, i, j, k;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering usec_t z, x;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!on_tty())
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering z = now(CLOCK_MONOTONIC);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering x = *last_usec;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (x != 0 && x + 40 * USEC_PER_MSEC > z)
2b6bf07dd23bb467099d213c97b3875c5e453491Zbigniew Jędrzejewski-Szmek return;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *last_usec = z;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering n = (3 * columns()) / 4;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering j = (n * (unsigned) p) / 65535ULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering k = n - j;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (i = 0; i < j; i++)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering fputs("\xe2\x96\x88", stdout);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering fputs(ANSI_HIGHLIGHT_OFF, stdout);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (i = 0; i < k; i++)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering fputs("\xe2\x96\x91", stdout);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering printf(" %3"PRIu64"%%", 100U * p / 65535U);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering fputs("\r\x1B[?25h", stdout);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering fflush(stdout);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering}
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic uint64_t scale_progress(uint64_t scale, uint64_t p, uint64_t m) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Calculates scale * p / m, but handles m == 0 safely, and saturates */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (p >= m || m == 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return scale;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return scale * p / m;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poetteringstatic void flush_progress(void) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering unsigned n, i;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!on_tty())
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return;
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering n = (3 * columns()) / 4;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering putchar('\r');
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (i = 0; i < n + 5; i++)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering putchar(' ');
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering putchar('\r');
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering fflush(stdout);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#define debug(_offset, _fmt, ...) do{ \
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering flush_progress(); \
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering log_debug(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } while(0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering#define warning(_offset, _fmt, ...) do{ \
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering flush_progress(); \
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering log_warning(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } while(0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering#define error(_offset, _fmt, ...) do{ \
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering flush_progress(); \
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering log_error(OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } while(0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poetteringstatic int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering uint64_t i;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(f);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(offset);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering assert(o);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* This does various superficial tests about the length an
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * possible field values. It does not follow any references to
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * other objects. */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->object.type != OBJECT_DATA) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset, "Found compressed object that isn't of type DATA, which is not allowed.");
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering switch (o->object.type) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering case OBJECT_DATA: {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering uint64_t h1, h2;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering int compression, r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (le64toh(o->data.entry_offset) == 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering warning(offset, "Unused data (entry_offset==0)");
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset, "Bad n_entries: %"PRIu64, o->data.n_entries);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset, "Bad object size (<= %zu): %"PRIu64,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering offsetof(DataObject, payload),
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->object.size));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering h1 = le64toh(o->data.hash);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering compression = o->object.flags & OBJECT_COMPRESSION_MASK;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (compression) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering _cleanup_free_ void *b = NULL;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering size_t alloc = 0, b_size;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = decompress_blob(compression,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->data.payload,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->object.size) - offsetof(Object, data.payload),
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering &b, &alloc, &b_size, 0);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (r < 0) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset, "%s decompression failed: %s",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering object_compressed_to_string(compression), strerror(-r));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering h2 = hash64(b, b_size);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (h1 != h2) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering error(offset, "Invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!VALID64(o->data.next_hash_offset) ||
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering !VALID64(o->data.next_field_offset) ||
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering !VALID64(o->data.entry_offset) ||
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering !VALID64(o->data.entry_array_offset)) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering error(offset, "Invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->data.next_hash_offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->data.next_field_offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->data.entry_offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->data.entry_array_offset);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering case OBJECT_FIELD:
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Bad field size (<= %zu): %"PRIu64,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering offsetof(FieldObject, payload),
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering le64toh(o->object.size));
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return -EBADMSG;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!VALID64(o->field.next_hash_offset) ||
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering !VALID64(o->field.head_data_offset)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->field.next_hash_offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->field.head_data_offset);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering case OBJECT_ENTRY:
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Bad entry size (<= %zu): %"PRIu64,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering offsetof(EntryObject, items),
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->object.size));
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return -EBADMSG;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering }
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn error(offset,
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn "Invalid number items in entry: %"PRIu64,
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem));
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return -EBADMSG;
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn }
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn if (le64toh(o->entry.seqnum) <= 0) {
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn error(offset,
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn "Invalid entry seqnum: %"PRIx64,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering le64toh(o->entry.seqnum));
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering error(offset,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "Invalid entry realtime timestamp: %"PRIu64,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->entry.realtime));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid entry monotonic timestamp: %"PRIu64,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering le64toh(o->entry.monotonic));
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (i = 0; i < journal_file_entry_n_items(o); i++) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (o->entry.items[i].object_offset == 0 ||
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering !VALID64(o->entry.items[i].object_offset)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering i, journal_file_entry_n_items(o),
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->entry.items[i].object_offset);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering break;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering case OBJECT_DATA_HASH_TABLE:
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering case OBJECT_FIELD_HASH_TABLE:
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering error(offset,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "Invalid %s hash table size: %"PRIu64,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering le64toh(o->object.size));
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return -EBADMSG;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (o->hash_table.items[i].head_hash_offset != 0 &&
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering i, journal_file_hash_table_n_items(o),
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->hash_table.items[i].head_hash_offset));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers if (o->hash_table.items[i].tail_hash_offset != 0 &&
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering i, journal_file_hash_table_n_items(o),
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->hash_table.items[i].tail_hash_offset));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if ((o->hash_table.items[i].head_hash_offset != 0) !=
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering (o->hash_table.items[i].tail_hash_offset != 0)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering i, journal_file_hash_table_n_items(o),
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->hash_table.items[i].head_hash_offset),
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering le64toh(o->hash_table.items[i].tail_hash_offset));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering case OBJECT_ENTRY_ARRAY:
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid object entry array size: %"PRIu64,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->object.size));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!VALID64(o->entry_array.next_entry_array_offset)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid object entry array next_entry_array_offset: "OFSfmt,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering o->entry_array.next_entry_array_offset);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering for (i = 0; i < journal_file_entry_array_n_items(o); i++)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (le64toh(o->entry_array.items[i]) != 0 &&
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering !VALID64(le64toh(o->entry_array.items[i]))) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering i, journal_file_entry_array_n_items(o),
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->entry_array.items[i]));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering case OBJECT_TAG:
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (le64toh(o->object.size) != sizeof(TagObject)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering "Invalid object tag size: %"PRIu64,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering le64toh(o->object.size));
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!VALID_EPOCH(o->tag.epoch)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(offset,
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering "Invalid object tag epoch: %"PRIu64,
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering o->tag.epoch);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return 0;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering}
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poetteringstatic int write_uint64(int fd, uint64_t p) {
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering ssize_t k;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering k = write(fd, &p, sizeof(p));
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering if (k < 0)
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering return -errno;
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering if (k != sizeof(p))
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering return -EIO;
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return 0;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering}
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poetteringstatic int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering uint64_t a, b;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering int r;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering assert(m);
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering assert(fd >= 0);
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering /* Bisection ... */
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering a = 0; b = n;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering while (a < b) {
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering uint64_t c, *z;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering c = (a + b) / 2;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering if (r < 0)
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering return r;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering if (*z == p)
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering return 1;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (a + 1 >= b)
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return 0;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering if (p < *z)
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering b = c;
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering else
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering a = c;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering }
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering return 0;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering}
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poetteringstatic int entry_points_to_data(
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering JournalFile *f,
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering int entry_fd,
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering uint64_t n_entries,
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering uint64_t entry_p,
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering uint64_t data_p) {
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering int r;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering uint64_t i, n, a;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering Object *o;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering bool found = false;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering assert(f);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(entry_fd >= 0);
ec202eae8e84a4c99f054f771cb832046cb8769fShawn Landden
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering error(data_p, "Data object references invalid entry at "OFSfmt, entry_p);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -EBADMSG;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (r < 0)
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return r;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering n = journal_file_entry_n_items(o);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering for (i = 0; i < n; i++)
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (le64toh(o->entry.items[i].object_offset) == data_p) {
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering found = true;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering break;
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering }
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering if (!found) {
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering error(entry_p, "Data object at "OFSfmt" not referenced by linked entry", data_p);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return -EBADMSG;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering }
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering /* Check if this entry is also in main entry array. Since the
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering * main entry array has already been verified we can rely on
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering * its consistency. */
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering i = 0;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering n = le64toh(f->header->n_entries);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering a = le64toh(f->header->entry_array_offset);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering while (i < n) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering uint64_t m, u;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r < 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering m = journal_file_entry_array_n_items(o);
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen u = MIN(n - i, m);
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen if (entry_p <= le64toh(o->entry_array.items[u-1])) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering uint64_t x, y, z;
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering x = 0;
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen y = u;
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen while (x < y) {
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering z = (x + y) / 2;
641906e9366891e0ad3e6e38b7396a427678c4cfThomas Hindoe Paaboel Andersen
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (le64toh(o->entry_array.items[z]) == entry_p)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (x + 1 >= y)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (entry_p < le64toh(o->entry_array.items[z]))
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering y = z;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering else
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering x = z;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering }
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering error(entry_p, "Entry object doesn't exist in main entry array");
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return -EBADMSG;
}
i += u;
a = le64toh(o->entry_array.next_entry_array_offset);
}
return 0;
}
static int verify_data(
JournalFile *f,
Object *o, uint64_t p,
int entry_fd, uint64_t n_entries,
int entry_array_fd, uint64_t n_entry_arrays) {
uint64_t i, n, a, last, q;
int r;
assert(f);
assert(o);
assert(entry_fd >= 0);
assert(entry_array_fd >= 0);
n = le64toh(o->data.n_entries);
a = le64toh(o->data.entry_array_offset);
/* Entry array means at least two objects */
if (a && n < 2) {
error(p, "Entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", a, n);
return -EBADMSG;
}
if (n == 0)
return 0;
/* We already checked that earlier */
assert(o->data.entry_offset);
last = q = le64toh(o->data.entry_offset);
r = entry_points_to_data(f, entry_fd, n_entries, q, p);
if (r < 0)
return r;
i = 1;
while (i < n) {
uint64_t next, m, j;
if (a == 0) {
error(p, "Array chain too short");
return -EBADMSG;
}
if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
error(p, "Invalid array offset "OFSfmt, a);
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
next = le64toh(o->entry_array.next_entry_array_offset);
if (next != 0 && next <= a) {
error(p, "Array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", a, next);
return -EBADMSG;
}
m = journal_file_entry_array_n_items(o);
for (j = 0; i < n && j < m; i++, j++) {
q = le64toh(o->entry_array.items[j]);
if (q <= last) {
error(p, "Data object's entry array not sorted");
return -EBADMSG;
}
last = q;
r = entry_points_to_data(f, entry_fd, n_entries, q, p);
if (r < 0)
return r;
/* Pointer might have moved, reposition */
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
}
a = next;
}
return 0;
}
static int verify_hash_table(
JournalFile *f,
int data_fd, uint64_t n_data,
int entry_fd, uint64_t n_entries,
int entry_array_fd, uint64_t n_entry_arrays,
usec_t *last_usec,
bool show_progress) {
uint64_t i, n;
int r;
assert(f);
assert(data_fd >= 0);
assert(entry_fd >= 0);
assert(entry_array_fd >= 0);
assert(last_usec);
n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
if (n <= 0)
return 0;
r = journal_file_map_data_hash_table(f);
if (r < 0)
return log_error_errno(r, "Failed to map data hash table: %m");
for (i = 0; i < n; i++) {
uint64_t last = 0, p;
if (show_progress)
draw_progress(0xC000 + scale_progress(0x3FFF, i, n), last_usec);
p = le64toh(f->data_hash_table[i].head_hash_offset);
while (p != 0) {
Object *o;
uint64_t next;
if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
error(p, "Invalid data object at hash entry %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
if (r < 0)
return r;
next = le64toh(o->data.next_hash_offset);
if (next != 0 && next <= p) {
error(p, "Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
if (le64toh(o->data.hash) % n != i) {
error(p, "Hash value mismatch in hash entry %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
if (r < 0)
return r;
last = p;
p = next;
}
if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
error(p, "Tail hash pointer mismatch in hash table");
return -EBADMSG;
}
}
return 0;
}
static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
uint64_t n, h, q;
int r;
assert(f);
n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
if (n <= 0)
return 0;
r = journal_file_map_data_hash_table(f);
if (r < 0)
return log_error_errno(r, "Failed to map data hash table: %m");
h = hash % n;
q = le64toh(f->data_hash_table[h].head_hash_offset);
while (q != 0) {
Object *o;
if (p == q)
return 1;
r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
if (r < 0)
return r;
q = le64toh(o->data.next_hash_offset);
}
return 0;
}
static int verify_entry(
JournalFile *f,
Object *o, uint64_t p,
int data_fd, uint64_t n_data) {
uint64_t i, n;
int r;
assert(f);
assert(o);
assert(data_fd >= 0);
n = journal_file_entry_n_items(o);
for (i = 0; i < n; i++) {
uint64_t q, h;
Object *u;
q = le64toh(o->entry.items[i].object_offset);
h = le64toh(o->entry.items[i].hash);
if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
error(p, "Invalid data object of entry");
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
if (r < 0)
return r;
if (le64toh(u->data.hash) != h) {
error(p, "Hash mismatch for data object of entry");
return -EBADMSG;
}
r = data_object_in_hash_table(f, h, q);
if (r < 0)
return r;
if (r == 0) {
error(p, "Data object missing from hash table");
return -EBADMSG;
}
}
return 0;
}
static int verify_entry_array(
JournalFile *f,
int data_fd, uint64_t n_data,
int entry_fd, uint64_t n_entries,
int entry_array_fd, uint64_t n_entry_arrays,
usec_t *last_usec,
bool show_progress) {
uint64_t i = 0, a, n, last = 0;
int r;
assert(f);
assert(data_fd >= 0);
assert(entry_fd >= 0);
assert(entry_array_fd >= 0);
assert(last_usec);
n = le64toh(f->header->n_entries);
a = le64toh(f->header->entry_array_offset);
while (i < n) {
uint64_t next, m, j;
Object *o;
if (show_progress)
draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec);
if (a == 0) {
error(a, "Array chain too short at %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
error(a, "Invalid array %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
next = le64toh(o->entry_array.next_entry_array_offset);
if (next != 0 && next <= a) {
error(a, "Array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", i, n, next);
return -EBADMSG;
}
m = journal_file_entry_array_n_items(o);
for (j = 0; i < n && j < m; i++, j++) {
uint64_t p;
p = le64toh(o->entry_array.items[j]);
if (p <= last) {
error(a, "Entry array not sorted at %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
last = p;
if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
error(a, "Invalid array entry at %"PRIu64" of %"PRIu64, i, n);
return -EBADMSG;
}
r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
if (r < 0)
return r;
r = verify_entry(f, o, p, data_fd, n_data);
if (r < 0)
return r;
/* Pointer might have moved, reposition */
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
if (r < 0)
return r;
}
a = next;
}
return 0;
}
int journal_file_verify(
JournalFile *f,
const char *key,
usec_t *first_contained, usec_t *last_validated, usec_t *last_contained,
bool show_progress) {
int r;
Object *o;
uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
sd_id128_t entry_boot_id;
bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
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;
usec_t last_usec = 0;
int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
unsigned i;
bool found_last = false;
#ifdef HAVE_GCRYPT
uint64_t last_tag = 0;
#endif
assert(f);
if (key) {
#ifdef HAVE_GCRYPT
r = journal_file_parse_verification_key(f, key);
if (r < 0) {
log_error("Failed to parse seed.");
return r;
}
#else
return -EOPNOTSUPP;
#endif
} else if (f->seal)
return -ENOKEY;
data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (data_fd < 0) {
r = log_error_errno(errno, "Failed to create data file: %m");
goto fail;
}
entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_fd < 0) {
r = log_error_errno(errno, "Failed to create entry file: %m");
goto fail;
}
entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_array_fd < 0) {
r = log_error_errno(errno,
"Failed to create entry array file: %m");
goto fail;
}
if (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SUPPORTED) {
log_error("Cannot verify file with unknown extensions.");
r = -EOPNOTSUPP;
goto fail;
}
for (i = 0; i < sizeof(f->header->reserved); i++)
if (f->header->reserved[i] != 0) {
error(offsetof(Header, reserved[i]), "Reserved field is non-zero");
r = -EBADMSG;
goto fail;
}
/* First iteration: we go through all objects, verify the
* superficial structure, headers, hashes. */
p = le64toh(f->header->header_size);
for (;;) {
/* Early exit if there are no objects in the file, at all */
if (le64toh(f->header->tail_object_offset) == 0)
break;
if (show_progress)
draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec);
r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0) {
error(p, "Invalid object");
goto fail;
}
if (p > le64toh(f->header->tail_object_offset)) {
error(offsetof(Header, tail_object_offset), "Invalid tail object pointer");
r = -EBADMSG;
goto fail;
}
n_objects ++;
r = journal_file_object_verify(f, p, o);
if (r < 0) {
error(p, "Envalid object contents: %s", strerror(-r));
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_XZ) &&
(o->object.flags & OBJECT_COMPRESSED_LZ4)) {
error(p, "Objected with double compression");
r = -EINVAL;
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) {
error(p, "XZ compressed object in file without XZ compression");
r = -EBADMSG;
goto fail;
}
if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) {
error(p, "LZ4 compressed object in file without LZ4 compression");
r = -EBADMSG;
goto fail;
}
switch (o->object.type) {
case OBJECT_DATA:
r = write_uint64(data_fd, p);
if (r < 0)
goto fail;
n_data++;
break;
case OBJECT_FIELD:
n_fields++;
break;
case OBJECT_ENTRY:
if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
error(p, "First entry before first tag");
r = -EBADMSG;
goto fail;
}
r = write_uint64(entry_fd, p);
if (r < 0)
goto fail;
if (le64toh(o->entry.realtime) < last_tag_realtime) {
error(p, "Older entry after newer tag");
r = -EBADMSG;
goto fail;
}
if (!entry_seqnum_set &&
le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
error(p, "Head entry sequence number incorrect");
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum >= le64toh(o->entry.seqnum)) {
error(p, "Entry sequence number out of synchronization");
r = -EBADMSG;
goto fail;
}
entry_seqnum = le64toh(o->entry.seqnum);
entry_seqnum_set = true;
if (entry_monotonic_set &&
sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
entry_monotonic > le64toh(o->entry.monotonic)) {
error(p, "Entry timestamp out of synchronization");
r = -EBADMSG;
goto fail;
}
entry_monotonic = le64toh(o->entry.monotonic);
entry_boot_id = o->entry.boot_id;
entry_monotonic_set = true;
if (!entry_realtime_set &&
le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
error(p, "Head entry realtime timestamp incorrect");
r = -EBADMSG;
goto fail;
}
entry_realtime = le64toh(o->entry.realtime);
entry_realtime_set = true;
n_entries ++;
break;
case OBJECT_DATA_HASH_TABLE:
if (n_data_hash_tables > 1) {
error(p, "More than one data hash table");
r = -EBADMSG;
goto fail;
}
if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
error(p, "header fields for data hash table invalid");
r = -EBADMSG;
goto fail;
}
n_data_hash_tables++;
break;
case OBJECT_FIELD_HASH_TABLE:
if (n_field_hash_tables > 1) {
error(p, "More than one field hash table");
r = -EBADMSG;
goto fail;
}
if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
error(p, "Header fields for field hash table invalid");
r = -EBADMSG;
goto fail;
}
n_field_hash_tables++;
break;
case OBJECT_ENTRY_ARRAY:
r = write_uint64(entry_array_fd, p);
if (r < 0)
goto fail;
if (p == le64toh(f->header->entry_array_offset)) {
if (found_main_entry_array) {
error(p, "More than one main entry array");
r = -EBADMSG;
goto fail;
}
found_main_entry_array = true;
}
n_entry_arrays++;
break;
case OBJECT_TAG:
if (!JOURNAL_HEADER_SEALED(f->header)) {
error(p, "Tag object in file without sealing");
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.seqnum) != n_tags + 1) {
error(p, "Tag sequence number out of synchronization");
r = -EBADMSG;
goto fail;
}
if (le64toh(o->tag.epoch) < last_epoch) {
error(p, "Epoch sequence out of synchronization");
r = -EBADMSG;
goto fail;
}
#ifdef HAVE_GCRYPT
if (f->seal) {
uint64_t q, rt;
debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
error(p, "tag/entry realtime timestamp out of synchronization");
r = -EBADMSG;
goto fail;
}
/* OK, now we know the epoch. So let's now set
* it, and calculate the HMAC for everything
* since the last tag. */
r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
if (r < 0)
goto fail;
r = journal_file_hmac_start(f);
if (r < 0)
goto fail;
if (last_tag == 0) {
r = journal_file_hmac_put_header(f);
if (r < 0)
goto fail;
q = le64toh(f->header->header_size);
} else
q = last_tag;
while (q <= p) {
r = journal_file_move_to_object(f, OBJECT_UNUSED, q, &o);
if (r < 0)
goto fail;
r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q);
if (r < 0)
goto fail;
q = q + ALIGN64(le64toh(o->object.size));
}
/* Position might have changed, let's reposition things */
r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0)
goto fail;
if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
error(p, "Tag failed verification");
r = -EBADMSG;
goto fail;
}
f->hmac_running = false;
last_tag_realtime = rt;
last_sealed_realtime = entry_realtime;
}
last_tag = p + ALIGN64(le64toh(o->object.size));
#endif
last_epoch = le64toh(o->tag.epoch);
n_tags ++;
break;
default:
n_weird ++;
}
if (p == le64toh(f->header->tail_object_offset)) {
found_last = true;
break;
}
p = p + ALIGN64(le64toh(o->object.size));
};
if (!found_last && le64toh(f->header->tail_object_offset) != 0) {
error(le64toh(f->header->tail_object_offset), "Tail object pointer dead");
r = -EBADMSG;
goto fail;
}
if (n_objects != le64toh(f->header->n_objects)) {
error(offsetof(Header, n_objects), "Object number mismatch");
r = -EBADMSG;
goto fail;
}
if (n_entries != le64toh(f->header->n_entries)) {
error(offsetof(Header, n_entries), "Entry number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
n_data != le64toh(f->header->n_data)) {
error(offsetof(Header, n_data), "Data number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
n_fields != le64toh(f->header->n_fields)) {
error(offsetof(Header, n_fields), "Field number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
n_tags != le64toh(f->header->n_tags)) {
error(offsetof(Header, n_tags), "Tag number mismatch");
r = -EBADMSG;
goto fail;
}
if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
error(offsetof(Header, n_entry_arrays), "Entry array number mismatch");
r = -EBADMSG;
goto fail;
}
if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) {
error(0, "Missing entry array");
r = -EBADMSG;
goto fail;
}
if (entry_seqnum_set &&
entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
error(offsetof(Header, tail_entry_seqnum), "Invalid tail seqnum");
r = -EBADMSG;
goto fail;
}
if (entry_monotonic_set &&
(!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
error(0, "Invalid tail monotonic timestamp");
r = -EBADMSG;
goto fail;
}
if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
error(0, "Invalid tail realtime timestamp");
r = -EBADMSG;
goto fail;
}
/* Second iteration: we follow all objects referenced from the
* two entry points: the object hash table and the entry
* array. We also check that everything referenced (directly
* or indirectly) in the data hash table also exists in the
* entry array, and vice versa. Note that we do not care for
* unreferenced objects. We only care that everything that is
* referenced is consistent. */
r = verify_entry_array(f,
data_fd, n_data,
entry_fd, n_entries,
entry_array_fd, n_entry_arrays,
&last_usec,
show_progress);
if (r < 0)
goto fail;
r = verify_hash_table(f,
data_fd, n_data,
entry_fd, n_entries,
entry_array_fd, n_entry_arrays,
&last_usec,
show_progress);
if (r < 0)
goto fail;
if (show_progress)
flush_progress();
mmap_cache_close_fd(f->mmap, data_fd);
mmap_cache_close_fd(f->mmap, entry_fd);
mmap_cache_close_fd(f->mmap, entry_array_fd);
safe_close(data_fd);
safe_close(entry_fd);
safe_close(entry_array_fd);
if (first_contained)
*first_contained = le64toh(f->header->head_entry_realtime);
if (last_validated)
*last_validated = last_sealed_realtime;
if (last_contained)
*last_contained = le64toh(f->header->tail_entry_realtime);
return 0;
fail:
if (show_progress)
flush_progress();
log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).",
f->path,
p,
(unsigned long long) f->last_stat.st_size,
100 * p / f->last_stat.st_size);
if (data_fd >= 0) {
mmap_cache_close_fd(f->mmap, data_fd);
safe_close(data_fd);
}
if (entry_fd >= 0) {
mmap_cache_close_fd(f->mmap, entry_fd);
safe_close(entry_fd);
}
if (entry_array_fd >= 0) {
mmap_cache_close_fd(f->mmap, entry_array_fd);
safe_close(entry_array_fd);
}
return r;
}