You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
systemd/SOURCES/0751-journal-do-not-rotate-...

137 lines
5.5 KiB

From 6e5dce6e2f9cc43375eb481c2d533606d2a07e1b Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 22 Apr 2024 17:25:31 +0900
Subject: [PATCH] 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.
(cherry picked from commit bd0ec61ae3bb7a5200b344bab46ba2d6b9406aac)
Resolves: RHEL-33890
---
src/journal/journald-server.c | 67 +++++++++++++++++++++++++----------
1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 56f2ea8583..0ff6a43e5b 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -667,6 +667,33 @@ void server_rotate(Server *s) {
server_process_deferred_closes(s);
}
+static void server_rotate_journal(Server *s, ManagedJournalFile *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) do_rotate(s, &s->system_journal, "system", s->seal, /* uid= */ 0);
+ else if (f == s->runtime_journal)
+ (void) 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 = 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) {
ManagedJournalFile *f;
int r;
@@ -819,7 +846,7 @@ static bool shall_try_append_again(JournalFile *f, int r) {
}
static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n, int priority) {
- bool vacuumed = false, rotate = false;
+ bool vacuumed = false;
struct dual_timestamp ts;
ManagedJournalFile *f;
int r;
@@ -841,23 +868,25 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
* bisection works correctly. */
log_info("Time jumped backwards, rotating.");
- rotate = true;
- } else {
+ server_rotate(s);
+ server_vacuum(s, /* verbose = */ false);
+ vacuumed = true;
+ }
- f = find_journal(s, uid);
- if (!f)
- return;
+ f = find_journal(s, uid);
+ if (!f)
+ return;
- if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_DEBUG)) {
- log_debug("%s: Journal header limits reached or header out-of-date, rotating.",
- f->file->path);
- rotate = true;
+ if (journal_file_rotate_suggested(f->file, s->max_file_usec, LOG_DEBUG)) {
+ if (vacuumed) {
+ log_warning("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->file->path);
+
+ server_rotate_journal(s, TAKE_PTR(f), uid);
+ server_vacuum(s, /* verbose = */ false);
vacuumed = true;
f = find_journal(s, uid);
@@ -883,8 +912,8 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, size_t n
else
log_ratelimit_full_errno(LOG_INFO, r, "Failed to write entry to %s (%zu items, %zu bytes), rotating before retrying: %m", f->file->path, n, IOVEC_TOTAL_SIZE(iovec, n));
- server_rotate(s);
- server_vacuum(s, false);
+ server_rotate_journal(s, TAKE_PTR(f), uid);
+ server_vacuum(s, /* verbose = */ false);
f = find_journal(s, uid);
if (!f)
@@ -1211,10 +1240,10 @@ int server_flush_to_var(Server *s, bool require_flag_file) {
log_info("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) {
+ if (!s->system_journal->file) {
log_notice("Didn't flush runtime journal since rotation of system journal wasn't successful.");
r = -EIO;
goto finish;