]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journal: do not rotate unrelated journal files when full or corrupted
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 22 Apr 2024 08:25:31 +0000 (17:25 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 23 Apr 2024 13:13:05 +0000 (15:13 +0200)
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.

src/journal/journald-server.c

index 285aea988ae25637bce4f2055df887d0869a9aa4..02895b2068bff36e1ce80bd70bff93b8325d3d52 100644 (file)
@@ -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,