diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-04-22 10:25:31 +0200 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@gmail.com> | 2024-04-23 15:13:05 +0200 |
commit | bd0ec61ae3bb7a5200b344bab46ba2d6b9406aac (patch) | |
tree | 3d97b3b7cc2ac568e1327b67b2ba65035783c646 /src | |
parent | core: Limit terminal reset using ANSI sequences to /dev/console (diff) | |
download | systemd-bd0ec61ae3bb7a5200b344bab46ba2d6b9406aac.tar.xz systemd-bd0ec61ae3bb7a5200b344bab46ba2d6b9406aac.zip |
journal: do not rotate unrelated journal files when full or corrupted
When we fail to add an entry to a journal file, typically when the file
is full or corrupted, it is not necessary to rotate other journal files.
Not only that's unnecessary, rotating all journal files allows
unprivileged users to wipe system or other user's journals by writing
many journal entries to their own user journal file.
Let's rotate all journal files only when
- it is really requested by a privileged user (e.g. by journalctl --rotate), or
- the system time jumps backwards.
And, otherwise rotate only the journal file we are currently writing.
Diffstat (limited to 'src')
-rw-r--r-- | src/journal/journald-server.c | 66 |
1 files changed, 48 insertions, 18 deletions
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 285aea988a..02895b2068 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -720,6 +720,33 @@ void server_rotate(Server *s) { server_process_deferred_closes(s); } +static void server_rotate_journal(Server *s, JournalFile *f, uid_t uid) { + int r; + + assert(s); + assert(f); + + /* This is similar to server_rotate(), but rotates only specified journal file. + * + * 💣💣💣 This invalidate 'f', and the caller cannot reuse the passed JournalFile object. 💣💣💣 */ + + if (f == s->system_journal) + (void) server_do_rotate(s, &s->system_journal, "system", s->seal, /* uid= */ 0); + else if (f == s->runtime_journal) + (void) server_do_rotate(s, &s->runtime_journal, "runtime", /* seal= */ false, /* uid= */ 0); + else { + assert(ordered_hashmap_get(s->user_journals, UID_TO_PTR(uid)) == f); + r = server_do_rotate(s, &f, "user", s->seal, uid); + if (r >= 0) + ordered_hashmap_replace(s->user_journals, UID_TO_PTR(uid), f); + else if (!f) + /* Old file has been closed and deallocated */ + ordered_hashmap_remove(s->user_journals, UID_TO_PTR(uid)); + } + + server_process_deferred_closes(s); +} + void server_sync(Server *s) { JournalFile *f; int r; @@ -904,7 +931,7 @@ static void server_write_to_journal( size_t n, int priority) { - bool vacuumed = false, rotate = false; + bool vacuumed = false; struct dual_timestamp ts; JournalFile *f; int r; @@ -926,23 +953,26 @@ static void server_write_to_journal( * bisection works correctly. */ log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "Time jumped backwards, rotating."); - rotate = true; - } else { + server_rotate(s); + server_vacuum(s, /* verbose = */ false); + vacuumed = true; + } - f = server_find_journal(s, uid); - if (!f) - return; + f = server_find_journal(s, uid); + if (!f) + return; - if (journal_file_rotate_suggested(f, s->max_file_usec, LOG_DEBUG)) { - log_debug("%s: Journal header limits reached or header out-of-date, rotating.", - f->path); - rotate = true; + if (journal_file_rotate_suggested(f, s->max_file_usec, LOG_DEBUG)) { + if (vacuumed) { + log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, + "Suppressing rotation, as we already rotated immediately before write attempt. Giving up."); + return; } - } - if (rotate) { - server_rotate(s); - server_vacuum(s, false); + log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path); + + server_rotate_journal(s, TAKE_PTR(f), uid); + server_vacuum(s, /* verbose = */ false); vacuumed = true; f = server_find_journal(s, uid); @@ -976,8 +1006,8 @@ static void server_write_to_journal( return; } - server_rotate(s); - server_vacuum(s, false); + server_rotate_journal(s, TAKE_PTR(f), uid); + server_vacuum(s, /* verbose = */ false); f = server_find_journal(s, uid); if (!f) @@ -1327,8 +1357,8 @@ int server_flush_to_var(Server *s, bool require_flag_file) { log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "Rotating system journal."); - server_rotate(s); - server_vacuum(s, false); + server_rotate_journal(s, s->system_journal, /* uid = */ 0); + server_vacuum(s, /* verbose = */ false); if (!s->system_journal) { log_ratelimit_notice(JOURNAL_LOG_RATELIMIT, |