Skip to content

Commit

Permalink
journal: do not rotate unrelated journal files when full or corrupted
Browse files Browse the repository at this point in the history
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 bd0ec61)

Resolves: RHEL-33890
  • Loading branch information
yuwata authored and dtardon committed May 15, 2024
1 parent f4c88e4 commit 991e614
Showing 1 changed file with 48 additions and 19 deletions.
67 changes: 48 additions & 19 deletions src/journal/journald-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 991e614

Please sign in to comment.