From aa00163d79309f9873512a4cc14a48c05fee7c65 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 7 Feb 2022 20:15:07 +0000 Subject: [PATCH 1/2] journal: Fix upwards iteration of entry items in case of corruption 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 | 40 +++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 67eb77be23..a2226da47b 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -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; } From 952d1e784a0ad47e0c2c832d28299987c3c25529 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 7 Feb 2022 20:19:29 +0000 Subject: [PATCH 2/2] journal: Improve handling of corruption during upwards entry iteration If we're going upwards in the journal file during entry iteration and we can't reach the current entry due to corruption, start iterating upwards from the last reachable entry array. This is equivalent to skipping all entries in the array that can't be reached anymore. Fixes #22431 --- src/libsystemd/sd-journal/journal-file.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index a2226da47b..ac8ad145ed 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -2224,6 +2224,24 @@ static int generic_array_get( while (a > 0) { r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) { + /* If there's corruption and we're going downwards, let's pretend we reached the + * final entry in the entry array chain. */ + + if (direction == DIRECTION_DOWN) + return 0; + + /* If there's corruption and we're going upwards, move back to the previous entry + * array and start iterating entries from there. */ + + r = bump_entry_array(f, NULL, a, first, DIRECTION_UP, &a); + if (r < 0) + return r; + + i = UINT64_MAX; + + break; + } if (r < 0) return r;