]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journal: Fix upwards iteration of entry items in case of corruption
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 7 Feb 2022 20:15:07 +0000 (20:15 +0000)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 7 Feb 2022 20:40:28 +0000 (20:40 +0000)
8d801e35cb155faa08235a5af8b4d6ad60715837 didn't take into account
upwards iteration of entry items when we're working on a corrupted
journal file. Instead of moving to the previous entry array, we'd
always move to the next array, regardless of the iteration direction.

To fix this, we introduce bump_entry_array() that moves to the next
or previous entry array depending on the given direction. Since the
entry array chains are singly linked lists, we have to start iterating
from the front to find the previous array. We only reach this logic
if we're working on a corrupted journal file so being slow here shouldn't
matter too much.

src/libsystemd/sd-journal/journal-file.c

index 67eb77be23f42d56134c90ec924553265926719a..a2226da47bee5869a4cb2900abc0c6bbbdb1b405 100644 (file)
@@ -2163,6 +2163,41 @@ static int bump_array_index(uint64_t *i, direction_t direction, uint64_t n) {
         return 1;
 }
 
+static int bump_entry_array(JournalFile *f, Object *o, uint64_t offset, uint64_t first, direction_t direction, uint64_t *ret) {
+        uint64_t p, q = 0;
+        int r;
+
+        assert(f);
+        assert(offset);
+        assert(ret);
+
+        if (direction == DIRECTION_DOWN)
+                return le64toh(o->entry_array.next_entry_array_offset);
+
+        /* Entry array chains are a singly linked list, so to find the previous array in the chain, we have
+         * to start iterating from the top. */
+
+        p = first;
+
+        while (p > 0 && p != offset) {
+                r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, p, &o);
+                if (r < 0)
+                        return r;
+
+                q = p;
+                p = le64toh(o->entry_array.next_entry_array_offset);
+        }
+
+        /* If we can't find the previous entry array in the entry array chain, we're likely dealing with a
+         * corrupted journal file. */
+        if (p == 0)
+                return -EBADMSG;
+
+        *ret = q;
+
+        return 0;
+}
+
 static int generic_array_get(
                 JournalFile *f,
                 uint64_t first,
@@ -2240,8 +2275,11 @@ static int generic_array_get(
                         log_debug_errno(r, "Entry item %" PRIu64 " is bad, skipping over it.", i);
                 } while (bump_array_index(&i, direction, k) > 0);
 
+                r = bump_entry_array(f, o, a, first, direction, &a);
+                if (r < 0)
+                        return r;
+
                 t += k;
-                a = le64toh(o->entry_array.next_entry_array_offset);
                 i = UINT64_MAX;
         }