diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 84e64aef6c..5c33c435e2 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -770,6 +770,169 @@ static uint64_t minimum_header_size(Object *o) { return table[o->object.type]; } +/* Lightweight object checks. We want this to be fast, so that we won't + * slowdown every journal_file_move_to_object() call too much. */ +static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o) { + assert(f); + assert(o); + + switch (o->object.type) { + + case OBJECT_DATA: { + if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) { + log_debug("Bad n_entries: %"PRIu64": %"PRIu64, + le64toh(o->data.n_entries), offset); + return -EBADMSG; + } + + if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) { + log_debug("Bad object size (<= %zu): %"PRIu64": %"PRIu64, + offsetof(DataObject, payload), + le64toh(o->object.size), + offset); + return -EBADMSG; + } + + if (!VALID64(le64toh(o->data.next_hash_offset)) || + !VALID64(le64toh(o->data.next_field_offset)) || + !VALID64(le64toh(o->data.entry_offset)) || + !VALID64(le64toh(o->data.entry_array_offset))) { + log_debug("Invalid offset, next_hash_offset="OFSfmt", next_field_offset="OFSfmt + ", entry_offset="OFSfmt", entry_array_offset="OFSfmt": %"PRIu64, + le64toh(o->data.next_hash_offset), + le64toh(o->data.next_field_offset), + le64toh(o->data.entry_offset), + le64toh(o->data.entry_array_offset), + offset); + return -EBADMSG; + } + + break; + } + + case OBJECT_FIELD: + if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) { + log_debug( + "Bad field size (<= %zu): %"PRIu64": %"PRIu64, + offsetof(FieldObject, payload), + le64toh(o->object.size), + offset); + return -EBADMSG; + } + + if (!VALID64(le64toh(o->field.next_hash_offset)) || + !VALID64(le64toh(o->field.head_data_offset))) { + log_debug( + "Invalid offset, next_hash_offset="OFSfmt + ", head_data_offset="OFSfmt": %"PRIu64, + le64toh(o->field.next_hash_offset), + le64toh(o->field.head_data_offset), + offset); + return -EBADMSG; + } + break; + + case OBJECT_ENTRY: + if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) { + log_debug( + "Bad entry size (<= %zu): %"PRIu64": %"PRIu64, + offsetof(EntryObject, items), + le64toh(o->object.size), + offset); + return -EBADMSG; + } + + if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) { + log_debug( + "Invalid number items in entry: %"PRIu64": %"PRIu64, + (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem), + offset); + return -EBADMSG; + } + + if (le64toh(o->entry.seqnum) <= 0) { + log_debug( + "Invalid entry seqnum: %"PRIx64": %"PRIu64, + le64toh(o->entry.seqnum), + offset); + return -EBADMSG; + } + + if (!VALID_REALTIME(le64toh(o->entry.realtime))) { + log_debug( + "Invalid entry realtime timestamp: %"PRIu64": %"PRIu64, + le64toh(o->entry.realtime), + offset); + return -EBADMSG; + } + + if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) { + log_debug( + "Invalid entry monotonic timestamp: %"PRIu64": %"PRIu64, + le64toh(o->entry.monotonic), + offset); + return -EBADMSG; + } + + break; + + case OBJECT_DATA_HASH_TABLE: + case OBJECT_FIELD_HASH_TABLE: + if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 || + (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) { + log_debug( + "Invalid %s hash table size: %"PRIu64": %"PRIu64, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + le64toh(o->object.size), + offset); + return -EBADMSG; + } + + break; + + case OBJECT_ENTRY_ARRAY: + if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 || + (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) { + log_debug( + "Invalid object entry array size: %"PRIu64": %"PRIu64, + le64toh(o->object.size), + offset); + return -EBADMSG; + } + + if (!VALID64(le64toh(o->entry_array.next_entry_array_offset))) { + log_debug( + "Invalid object entry array next_entry_array_offset: "OFSfmt": %"PRIu64, + le64toh(o->entry_array.next_entry_array_offset), + offset); + return -EBADMSG; + } + + break; + + case OBJECT_TAG: + if (le64toh(o->object.size) != sizeof(TagObject)) { + log_debug( + "Invalid object tag size: %"PRIu64": %"PRIu64, + le64toh(o->object.size), + offset); + return -EBADMSG; + } + + if (!VALID_EPOCH(le64toh(o->tag.epoch))) { + log_debug( + "Invalid object tag epoch: %"PRIu64": %"PRIu64, + le64toh(o->tag.epoch), + offset); + return -EBADMSG; + } + + break; + } + + return 0; +} + int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret) { int r; void *t; @@ -831,6 +994,10 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset o = (Object*) t; } + r = journal_file_check_object(f, offset, o); + if (r < 0) + return r; + *ret = o; return 0; }