journal-verify.c revision a2e99cdf94a8a0350ff13b241de07f34c015b1fc
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering This file is part of systemd.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Copyright 2012 Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (at your option) any later version.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering systemd is distributed in the hope that it will be useful, but
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Lesser General Public License for more details.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering * - evolve key even if nothing happened in regular intervals
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering * - add macro for accessing flags
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering * - Allow building without libgcrypt
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering * - check with sparse
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering * - 64bit conversions
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int journal_file_object_verify(JournalFile *f, Object *o) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* This does various superficial tests about the length an
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering * possible field values. It does not follow any references to
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering * other objects. */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if ((o->object.flags & OBJECT_COMPRESSED) &&
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (le64toh(o->data.entry_offset) <= 0 ||
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (o->object.flags & OBJECT_COMPRESSED) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering le64toh(o->object.size) - offsetof(Object, data.payload),
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
return -EBADMSG;
return -EBADMSG;
case OBJECT_FIELD:
return -EBADMSG;
return -EBADMSG;
case OBJECT_ENTRY:
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
for (i = 0; i < journal_file_entry_n_items(o); i++) {
return -EBADMSG;
case OBJECT_DATA_HASH_TABLE:
case OBJECT_FIELD_HASH_TABLE:
return -EBADMSG;
return -EBADMSG;
for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
case OBJECT_ENTRY_ARRAY:
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
for (i = 0; i < journal_file_entry_array_n_items(o); i++)
return -EBADMSG;
case OBJECT_TAG:
return -EBADMSG;
return -EBADMSG;
usec_t z, x;
x = *last_usec;
*last_usec = z;
static void flush_progress(void) {
ssize_t k;
return -errno;
return -EIO;
uint64_t a, b;
assert(m);
uint64_t c, *z;
r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
static int entry_points_to_data(
JournalFile *f,
int entry_fd,
uint64_t i, n, a;
Object *o;
bool found = false;
assert(f);
return -EBADMSG;
n = journal_file_entry_n_items(o);
found = true;
if (!found) {
return -EBADMSG;
uint64_t m, j;
m = journal_file_entry_array_n_items(o);
static int verify_data(
JournalFile *f,
assert(f);
assert(o);
assert(n > 0);
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
m = journal_file_entry_array_n_items(o);
if (q <= last) {
return -EBADMSG;
last = q;
a = next;
static int verify_hash_table(
JournalFile *f,
bool show_progress) {
uint64_t i, n;
assert(f);
if (show_progress)
Object *o;
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
last = p;
p = next;
return -EBADMSG;
uint64_t n, h, q;
assert(f);
h = hash % n;
Object *o;
static int verify_entry(
JournalFile *f,
uint64_t i, n;
assert(f);
assert(o);
n = journal_file_entry_n_items(o);
uint64_t q, h;
Object *u;
return -EBADMSG;
return -EBADMSG;
r = data_object_in_hash_table(f, h, q);
return -EBADMSG;
static int verify_entry_array(
JournalFile *f,
bool show_progress) {
assert(f);
Object *o;
if (show_progress)
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
m = journal_file_entry_array_n_items(o);
uint64_t p;
if (p <= last) {
return -EBADMSG;
last = p;
return -EBADMSG;
a = next;
if (!seed)
return -ENOMEM;
k = key;
for (c = 0; c < seed_size; c++) {
x = unhexchar(*k);
return -EINVAL;
y = unhexchar(*k);
return -EINVAL;
return -EINVAL;
return -EINVAL;
int journal_file_verify(
JournalFile *f,
const char *key,
bool show_progress) {
Object *o;
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;
bool found_last;
assert(f);
if (key) {
} else if (f->seal)
return -ENOKEY;
if (data_fd < 0) {
r = -errno;
goto fail;
if (entry_fd < 0) {
r = -errno;
goto fail;
if (entry_array_fd < 0) {
r = -errno;
goto fail;
#ifdef HAVE_GCRYPT
r = -ENOTSUP;
goto fail;
r = -EBADMSG;
goto fail;
if (show_progress)
goto fail;
r = -EBADMSG;
goto fail;
found_last = true;
n_objects ++;
r = journal_file_object_verify(f, o);
goto fail;
r = -EBADMSG;
goto fail;
case OBJECT_DATA:
goto fail;
n_data++;
case OBJECT_FIELD:
n_fields++;
case OBJECT_ENTRY:
r = -EBADMSG;
goto fail;
goto fail;
r = -EBADMSG;
goto fail;
if (!entry_seqnum_set &&
r = -EBADMSG;
goto fail;
if (entry_seqnum_set &&
r = -EBADMSG;
goto fail;
entry_seqnum_set = true;
if (entry_monotonic_set &&
r = -EBADMSG;
goto fail;
entry_monotonic_set = true;
if (!entry_realtime_set &&
r = -EBADMSG;
goto fail;
entry_realtime_set = true;
n_entries ++;
case OBJECT_DATA_HASH_TABLE:
r = -EBADMSG;
goto fail;
le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
r = -EBADMSG;
goto fail;
case OBJECT_FIELD_HASH_TABLE:
r = -EBADMSG;
goto fail;
le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
r = -EBADMSG;
goto fail;
case OBJECT_ENTRY_ARRAY:
goto fail;
if (found_main_entry_array) {
r = -EBADMSG;
goto fail;
found_main_entry_array = true;
case OBJECT_TAG: {
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
if (f->seal) {
r = -EBADMSG;
goto fail;
goto fail;
r = journal_file_hmac_start(f);
goto fail;
if (last_tag == 0) {
r = journal_file_hmac_put_header(f);
goto fail;
q = last_tag;
goto fail;
goto fail;
goto fail;
r = -EBADMSG;
goto fail;
f->hmac_running = false;
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) {