journal-verify.c revision c586dbf110abdbf0317bdd0f0a5900d709194409
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen This file is part of systemd.
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen Copyright 2012 Lennart Poettering
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen systemd is free software; you can redistribute it and/or modify it
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen under the terms of the GNU Lesser General Public License as published by
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen the Free Software Foundation; either version 2.1 of the License, or
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen (at your option) any later version.
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen systemd is distributed in the hope that it will be useful, but
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen WITHOUT ANY WARRANTY; without even the implied warranty of
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen Lesser General Public License for more details.
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen You should have received a copy of the GNU Lesser General Public License
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen along with systemd; If not, see <http://www.gnu.org/licenses/>.
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen * - write bit mucking test
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen * - evolve key even if nothing happened in regular intervals
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen * - Allow building without libgcrypt
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen * - check with sparse
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen * - 64bit conversions
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensenstatic int journal_file_object_verify(JournalFile *f, Object *o) {
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen /* This does various superficial tests about the length an
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen * possible field values. It does not follow any references to
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen * other objects. */
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen if ((o->object.flags & OBJECT_COMPRESSED) &&
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen if (le64toh(o->data.entry_offset) <= 0 ||
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
void *b = NULL;
return -EBADMSG;
free(b);
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;
case OBJECT_ENTRY_ARRAY:
return -EBADMSG;
return -EBADMSG;
return -EBADMSG;
case OBJECT_TAG:
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,
uint64_t i, n;
assert(f);
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,
assert(f);
Object *o;
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,
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;
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;
goto fail;
r = -EBADMSG;
goto fail;
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 ++;
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,
&last_usec);
goto fail;
r = verify_hash_table(f,
&last_usec);
goto fail;
if (first_validated)
if (last_validated)
if (last_contained)
fail:
f->path,
if (data_fd >= 0) {
if (entry_fd >= 0) {
if (entry_array_fd >= 0) {