summaryrefslogtreecommitdiff
path: root/src/journal/journal-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/journal/journal-file.c')
-rw-r--r--src/journal/journal-file.c190
1 files changed, 129 insertions, 61 deletions
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index bd53635860..b1e092224f 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -533,7 +533,7 @@ static int journal_file_verify_header(JournalFile *f) {
if (f->header->state >= _STATE_MAX)
return -EBADMSG;
- header_size = le64toh(f->header->header_size);
+ header_size = le64toh(READ_NOW(f->header->header_size));
/* The first addition was n_data, so check that we are at least this large */
if (header_size < HEADER_SIZE_MIN)
@@ -542,7 +542,7 @@ static int journal_file_verify_header(JournalFile *f) {
if (JOURNAL_HEADER_SEALED(f->header) && !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
return -EBADMSG;
- arena_size = le64toh(f->header->arena_size);
+ arena_size = le64toh(READ_NOW(f->header->arena_size));
if (UINT64_MAX - header_size < arena_size || header_size + arena_size > (uint64_t) f->last_stat.st_size)
return -ENODATA;
@@ -625,26 +625,29 @@ int journal_file_fstat(JournalFile *f) {
}
static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
- uint64_t old_size, new_size;
+ uint64_t old_size, new_size, old_header_size, old_arena_size;
int r;
assert(f);
assert(f->header);
- /* We assume that this file is not sparse, and we know that
- * for sure, since we always call posix_fallocate()
- * ourselves */
+ /* We assume that this file is not sparse, and we know that for sure, since we always call
+ * posix_fallocate() ourselves */
+
+ if (size > PAGE_ALIGN_DOWN(UINT64_MAX) - offset)
+ return -EINVAL;
if (mmap_cache_got_sigbus(f->mmap, f->cache_fd))
return -EIO;
- old_size =
- le64toh(f->header->header_size) +
- le64toh(f->header->arena_size);
+ old_header_size = le64toh(READ_NOW(f->header->header_size));
+ old_arena_size = le64toh(READ_NOW(f->header->arena_size));
+ if (old_arena_size > PAGE_ALIGN_DOWN(UINT64_MAX) - old_header_size)
+ return -EBADMSG;
+
+ old_size = old_header_size + old_arena_size;
- new_size = PAGE_ALIGN(offset + size);
- if (new_size < le64toh(f->header->header_size))
- new_size = le64toh(f->header->header_size);
+ new_size = MAX(PAGE_ALIGN(offset + size), old_header_size);
if (new_size <= old_size) {
@@ -690,7 +693,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
if (r != 0)
return -r;
- f->header->arena_size = htole64(new_size - le64toh(f->header->header_size));
+ f->header->arena_size = htole64(new_size - old_header_size);
return journal_file_fstat(f);
}
@@ -702,7 +705,15 @@ static unsigned type_to_context(ObjectType type) {
return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0;
}
-static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, void **ret, size_t *ret_size) {
+static int journal_file_move_to(
+ JournalFile *f,
+ ObjectType type,
+ bool keep_always,
+ uint64_t offset,
+ uint64_t size,
+ void **ret,
+ size_t *ret_size) {
+
int r;
assert(f);
@@ -711,6 +722,9 @@ static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_alway
if (size <= 0)
return -EINVAL;
+ if (size > UINT64_MAX - offset)
+ return -EBADMSG;
+
/* Avoid SIGBUS on invalid accesses */
if (offset + size > (uint64_t) f->last_stat.st_size) {
/* Hmm, out of range? Let's refresh the fstat() data
@@ -760,7 +774,7 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
le64toh(o->data.n_entries),
offset);
- if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
+ if (le64toh(o->object.size) <= offsetof(DataObject, payload))
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Bad object size (<= %zu): %" PRIu64 ": %" PRIu64,
offsetof(DataObject, payload),
@@ -782,7 +796,7 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
break;
case OBJECT_FIELD:
- if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
+ if (le64toh(o->object.size) <= offsetof(FieldObject, payload))
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Bad field size (<= %zu): %" PRIu64 ": %" PRIu64,
offsetof(FieldObject, payload),
@@ -798,18 +812,22 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
offset);
break;
- case OBJECT_ENTRY:
- if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
+ case OBJECT_ENTRY: {
+ uint64_t sz;
+
+ sz = le64toh(READ_NOW(o->object.size));
+ if (sz < offsetof(EntryObject, items) ||
+ (sz - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Bad entry size (<= %zu): %" PRIu64 ": %" PRIu64,
offsetof(EntryObject, items),
- le64toh(o->object.size),
+ sz,
offset);
- if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
+ if ((sz - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Invalid number items in entry: %" PRIu64 ": %" PRIu64,
- (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem),
+ (sz - offsetof(EntryObject, items)) / sizeof(EntryItem),
offset);
if (le64toh(o->entry.seqnum) <= 0)
@@ -831,25 +849,35 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
offset);
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)
+ case OBJECT_FIELD_HASH_TABLE: {
+ uint64_t sz;
+
+ sz = le64toh(READ_NOW(o->object.size));
+ if (sz < offsetof(HashTableObject, items) ||
+ (sz - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
+ (sz - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Invalid %s hash table size: %" PRIu64 ": %" PRIu64,
o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
- le64toh(o->object.size),
+ sz,
offset);
break;
+ }
+
+ case OBJECT_ENTRY_ARRAY: {
+ uint64_t sz;
- 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)
+ sz = le64toh(READ_NOW(o->object.size));
+ if (sz < offsetof(EntryArrayObject, items) ||
+ (sz - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
+ (sz - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Invalid object entry array size: %" PRIu64 ": %" PRIu64,
- le64toh(o->object.size),
+ sz,
offset);
if (!VALID64(le64toh(o->entry_array.next_entry_array_offset)))
@@ -859,6 +887,7 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
offset);
break;
+ }
case OBJECT_TAG:
if (le64toh(o->object.size) != sizeof(TagObject))
@@ -905,7 +934,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset
return r;
o = (Object*) t;
- s = le64toh(o->object.size);
+ s = le64toh(READ_NOW(o->object.size));
if (s == 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
@@ -995,11 +1024,21 @@ int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, O
if (p == 0)
p = le64toh(f->header->header_size);
else {
+ uint64_t sz;
+
r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &tail);
if (r < 0)
return r;
- p += ALIGN64(le64toh(tail->object.size));
+ sz = le64toh(READ_NOW(tail->object.size));
+ if (sz > UINT64_MAX - sizeof(uint64_t) + 1)
+ return -EBADMSG;
+
+ sz = ALIGN64(sz);
+ if (p > UINT64_MAX - sz)
+ return -EBADMSG;
+
+ p += sz;
}
r = journal_file_allocate(f, p, size);
@@ -1011,10 +1050,10 @@ int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, O
return r;
o = (Object*) t;
-
- zero(o->object);
- o->object.type = type;
- o->object.size = htole64(size);
+ o->object = (ObjectHeader) {
+ .type = type,
+ .size = htole64(size),
+ };
f->header->tail_object_offset = htole64(p);
f->header->n_objects = htole64(le64toh(f->header->n_objects) + 1);
@@ -1156,7 +1195,7 @@ static int journal_file_link_field(
if (o->object.type != OBJECT_FIELD)
return -EINVAL;
- m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
+ m = le64toh(READ_NOW(f->header->field_hash_table_size)) / sizeof(HashItem);
if (m <= 0)
return -EBADMSG;
@@ -1201,7 +1240,7 @@ static int journal_file_link_data(
if (o->object.type != OBJECT_DATA)
return -EINVAL;
- m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
+ m = le64toh(READ_NOW(f->header->data_hash_table_size)) / sizeof(HashItem);
if (m <= 0)
return -EBADMSG;
@@ -1257,7 +1296,7 @@ int journal_file_find_field_object_with_hash(
osize = offsetof(Object, field.payload) + size;
- m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
+ m = le64toh(READ_NOW(f->header->field_hash_table_size)) / sizeof(HashItem);
if (m <= 0)
return -EBADMSG;
@@ -1329,7 +1368,7 @@ int journal_file_find_data_object_with_hash(
osize = offsetof(Object, data.payload) + size;
- m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
+ m = le64toh(READ_NOW(f->header->data_hash_table_size)) / sizeof(HashItem);
if (m <= 0)
return -EBADMSG;
@@ -1351,7 +1390,7 @@ int journal_file_find_data_object_with_hash(
uint64_t l;
size_t rsize = 0;
- l = le64toh(o->object.size);
+ l = le64toh(READ_NOW(o->object.size));
if (l <= offsetof(Object, data.payload))
return -EBADMSG;
@@ -1576,30 +1615,47 @@ static int journal_file_append_data(
}
uint64_t journal_file_entry_n_items(Object *o) {
+ uint64_t sz;
assert(o);
if (o->object.type != OBJECT_ENTRY)
return 0;
- return (le64toh(o->object.size) - offsetof(Object, entry.items)) / sizeof(EntryItem);
+ sz = le64toh(READ_NOW(o->object.size));
+ if (sz < offsetof(Object, entry.items))
+ return 0;
+
+ return (sz - offsetof(Object, entry.items)) / sizeof(EntryItem);
}
uint64_t journal_file_entry_array_n_items(Object *o) {
+ uint64_t sz;
+
assert(o);
if (o->object.type != OBJECT_ENTRY_ARRAY)
return 0;
- return (le64toh(o->object.size) - offsetof(Object, entry_array.items)) / sizeof(uint64_t);
+ sz = le64toh(READ_NOW(o->object.size));
+ if (sz < offsetof(Object, entry_array.items))
+ return 0;
+
+ return (sz - offsetof(Object, entry_array.items)) / sizeof(uint64_t);
}
uint64_t journal_file_hash_table_n_items(Object *o) {
+ uint64_t sz;
+
assert(o);
if (!IN_SET(o->object.type, OBJECT_DATA_HASH_TABLE, OBJECT_FIELD_HASH_TABLE))
return 0;
- return (le64toh(o->object.size) - offsetof(Object, hash_table.items)) / sizeof(HashItem);
+ sz = le64toh(READ_NOW(o->object.size));
+ if (sz < offsetof(Object, hash_table.items))
+ return 0;
+
+ return (sz - offsetof(Object, hash_table.items)) / sizeof(HashItem);
}
static int link_entry_into_array(JournalFile *f,
@@ -1617,7 +1673,7 @@ static int link_entry_into_array(JournalFile *f,
assert(p > 0);
a = le64toh(*first);
- i = hidx = le64toh(*idx);
+ i = hidx = le64toh(READ_NOW(*idx));
while (a > 0) {
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
@@ -1682,6 +1738,7 @@ static int link_entry_into_array_plus_one(JournalFile *f,
le64_t *idx,
uint64_t p) {
+ uint64_t hidx;
int r;
assert(f);
@@ -1690,32 +1747,33 @@ static int link_entry_into_array_plus_one(JournalFile *f,
assert(idx);
assert(p > 0);
- if (*idx == 0)
+ hidx = le64toh(READ_NOW(*idx));
+ if (hidx == UINT64_MAX)
+ return -EBADMSG;
+ if (hidx == 0)
*extra = htole64(p);
else {
le64_t i;
- i = htole64(le64toh(*idx) - 1);
+ i = htole64(hidx - 1);
r = link_entry_into_array(f, first, &i, p);
if (r < 0)
return r;
}
- *idx = htole64(le64toh(*idx) + 1);
+ *idx = htole64(hidx + 1);
return 0;
}
static int journal_file_link_entry_item(JournalFile *f, Object *o, uint64_t offset, uint64_t i) {
uint64_t p;
int r;
+
assert(f);
assert(o);
assert(offset > 0);
p = le64toh(o->entry.items[i].object_offset);
- if (p == 0)
- return -EINVAL;
-
r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
if (r < 0)
return r;
@@ -2435,6 +2493,7 @@ _pure_ static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle
}
static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
+ uint64_t sq;
Object *o;
int r;
@@ -2445,9 +2504,10 @@ static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
if (r < 0)
return r;
- if (le64toh(o->entry.seqnum) == needle)
+ sq = le64toh(READ_NOW(o->entry.seqnum));
+ if (sq == needle)
return TEST_FOUND;
- else if (le64toh(o->entry.seqnum) < needle)
+ else if (sq < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
@@ -2473,6 +2533,7 @@ int journal_file_move_to_entry_by_seqnum(
static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
+ uint64_t rt;
int r;
assert(f);
@@ -2482,9 +2543,10 @@ static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) {
if (r < 0)
return r;
- if (le64toh(o->entry.realtime) == needle)
+ rt = le64toh(READ_NOW(o->entry.realtime));
+ if (rt == needle)
return TEST_FOUND;
- else if (le64toh(o->entry.realtime) < needle)
+ else if (rt < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
@@ -2510,6 +2572,7 @@ int journal_file_move_to_entry_by_realtime(
static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
+ uint64_t m;
int r;
assert(f);
@@ -2519,9 +2582,10 @@ static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) {
if (r < 0)
return r;
- if (le64toh(o->entry.monotonic) == needle)
+ m = le64toh(READ_NOW(o->entry.monotonic));
+ if (m == needle)
return TEST_FOUND;
- else if (le64toh(o->entry.monotonic) < needle)
+ else if (m < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
@@ -2679,7 +2743,7 @@ int journal_file_next_entry(
assert(f);
assert(f->header);
- n = le64toh(f->header->n_entries);
+ n = le64toh(READ_NOW(f->header->n_entries));
if (n <= 0)
return 0;
@@ -2752,7 +2816,7 @@ int journal_file_next_entry_for_data(
if (r < 0)
return r;
- n = le64toh(d->data.n_entries);
+ n = le64toh(READ_NOW(d->data.n_entries));
if (n <= 0)
return n;
@@ -2981,7 +3045,7 @@ void journal_file_dump(JournalFile *f) {
journal_file_print_header(f);
- p = le64toh(f->header->header_size);
+ p = le64toh(READ_NOW(f->header->header_size));
while (p != 0) {
r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0)
@@ -3038,7 +3102,7 @@ void journal_file_dump(JournalFile *f) {
if (p == le64toh(f->header->tail_object_offset))
p = 0;
else
- p = p + ALIGN64(le64toh(o->object.size));
+ p += ALIGN64(le64toh(o->object.size));
}
return;
@@ -3659,7 +3723,11 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
if (le_hash != o->data.hash)
return -EBADMSG;
- l = le64toh(o->object.size) - offsetof(Object, data.payload);
+ l = le64toh(READ_NOW(o->object.size));
+ if (l < offsetof(Object, data.payload))
+ return -EBADMSG;
+
+ l -= offsetof(Object, data.payload);
t = (size_t) l;
/* We hit the limit on 32bit machines */