dcavalca / rpms / systemd

Forked from rpms/systemd 4 months ago
Clone
6f381c
From 538bd9b42dabf1145cf7ab77f32347d516b01e88 Mon Sep 17 00:00:00 2001
6f381c
From: Lennart Poettering <lennart@poettering.net>
6f381c
Date: Tue, 12 May 2020 18:56:34 +0200
6f381c
Subject: [PATCH] journald: rework pid change handling
6f381c
6f381c
Let's introduce an explicit line ending marker for line endings due to
6f381c
pid change.
6f381c
6f381c
Let's also make sure we don't get confused with buffer management.
6f381c
6f381c
Fixes: #15654
6f381c
(cherry picked from commit 45ba1ea5e9264d385fa565328fe957ef1d78caa1)
6f381c
6f381c
Resolves: #2029426
6f381c
---
6f381c
 src/journal/journald-stream.c | 99 +++++++++++++++++++++++------------
6f381c
 1 file changed, 66 insertions(+), 33 deletions(-)
6f381c
6f381c
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
6f381c
index ab1a855943..5be5b0939c 100644
6f381c
--- a/src/journal/journald-stream.c
6f381c
+++ b/src/journal/journald-stream.c
6f381c
@@ -54,6 +54,7 @@ typedef enum LineBreak {
6f381c
         LINE_BREAK_NUL,
6f381c
         LINE_BREAK_LINE_MAX,
6f381c
         LINE_BREAK_EOF,
6f381c
+        LINE_BREAK_PID_CHANGE,
6f381c
         _LINE_BREAK_MAX,
6f381c
         _LINE_BREAK_INVALID = -1,
6f381c
 } LineBreak;
6f381c
@@ -310,6 +311,7 @@ static int stdout_stream_log(
6f381c
                 [LINE_BREAK_NUL]        = "_LINE_BREAK=nul",
6f381c
                 [LINE_BREAK_LINE_MAX]   = "_LINE_BREAK=line-max",
6f381c
                 [LINE_BREAK_EOF]        = "_LINE_BREAK=eof",
6f381c
+                [LINE_BREAK_PID_CHANGE] = "_LINE_BREAK=pid-change",
6f381c
         };
6f381c
 
6f381c
         const char *c = line_break_field_table[line_break];
6f381c
@@ -431,21 +433,43 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
6f381c
         assert_not_reached("Unknown stream state");
6f381c
 }
6f381c
 
6f381c
-static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
6f381c
-        char *p;
6f381c
-        size_t remaining;
6f381c
+static int stdout_stream_found(
6f381c
+                StdoutStream *s,
6f381c
+                char *p,
6f381c
+                size_t l,
6f381c
+                LineBreak line_break) {
6f381c
+
6f381c
+        char saved;
6f381c
         int r;
6f381c
 
6f381c
         assert(s);
6f381c
+        assert(p);
6f381c
+
6f381c
+        /* Let's NUL terminate the specified buffer for this call, and revert back afterwards */
6f381c
+        saved = p[l];
6f381c
+        p[l] = 0;
6f381c
+        r = stdout_stream_line(s, p, line_break);
6f381c
+        p[l] = saved;
6f381c
 
6f381c
-        p = s->buffer;
6f381c
-        remaining = s->length;
6f381c
+        return r;
6f381c
+}
6f381c
+
6f381c
+static int stdout_stream_scan(
6f381c
+                StdoutStream *s,
6f381c
+                char *p,
6f381c
+                size_t remaining,
6f381c
+                LineBreak force_flush,
6f381c
+                size_t *ret_consumed) {
6f381c
 
6f381c
-        /* XXX: This function does nothing if (s->length == 0) */
6f381c
+        size_t consumed = 0;
6f381c
+        int r;
6f381c
+
6f381c
+        assert(s);
6f381c
+        assert(p);
6f381c
 
6f381c
         for (;;) {
6f381c
                 LineBreak line_break;
6f381c
-                size_t skip;
6f381c
+                size_t skip, found;
6f381c
                 char *end1, *end2;
6f381c
 
6f381c
                 end1 = memchr(p, '\n', remaining);
6f381c
@@ -453,43 +477,40 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
6f381c
 
6f381c
                 if (end2) {
6f381c
                         /* We found a NUL terminator */
6f381c
-                        skip = end2 - p + 1;
6f381c
+                        found = end2 - p;
6f381c
+                        skip = found + 1;
6f381c
                         line_break = LINE_BREAK_NUL;
6f381c
                 } else if (end1) {
6f381c
                         /* We found a \n terminator */
6f381c
-                        *end1 = 0;
6f381c
-                        skip = end1 - p + 1;
6f381c
+                        found = end1 - p;
6f381c
+                        skip = found + 1;
6f381c
                         line_break = LINE_BREAK_NEWLINE;
6f381c
                 } else if (remaining >= s->server->line_max) {
6f381c
                         /* Force a line break after the maximum line length */
6f381c
-                        *(p + s->server->line_max) = 0;
6f381c
-                        skip = remaining;
6f381c
+                        found = skip = s->server->line_max;
6f381c
                         line_break = LINE_BREAK_LINE_MAX;
6f381c
                 } else
6f381c
                         break;
6f381c
 
6f381c
-                r = stdout_stream_line(s, p, line_break);
6f381c
+                r = stdout_stream_found(s, p, found, line_break);
6f381c
                 if (r < 0)
6f381c
                         return r;
6f381c
 
6f381c
-                remaining -= skip;
6f381c
                 p += skip;
6f381c
+                consumed += skip;
6f381c
+                remaining -= skip;
6f381c
         }
6f381c
 
6f381c
-        if (force_flush && remaining > 0) {
6f381c
-                p[remaining] = 0;
6f381c
-                r = stdout_stream_line(s, p, LINE_BREAK_EOF);
6f381c
+        if (force_flush >= 0 && remaining > 0) {
6f381c
+                r = stdout_stream_found(s, p, remaining, force_flush);
6f381c
                 if (r < 0)
6f381c
                         return r;
6f381c
 
6f381c
-                p += remaining;
6f381c
-                remaining = 0;
6f381c
+                consumed += remaining;
6f381c
         }
6f381c
 
6f381c
-        if (p > s->buffer) {
6f381c
-                memmove(s->buffer, p, remaining);
6f381c
-                s->length = remaining;
6f381c
-        }
6f381c
+        if (ret_consumed)
6f381c
+                *ret_consumed = consumed;
6f381c
 
6f381c
         return 0;
6f381c
 }
6f381c
@@ -497,11 +518,12 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
6f381c
 static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
6f381c
         uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
6f381c
         StdoutStream *s = userdata;
6f381c
+        size_t limit, consumed;
6f381c
         struct ucred *ucred = NULL;
6f381c
         struct cmsghdr *cmsg;
6f381c
         struct iovec iovec;
6f381c
-        size_t limit;
6f381c
         ssize_t l;
6f381c
+        char *p;
6f381c
         int r;
6f381c
 
6f381c
         struct msghdr msghdr = {
6f381c
@@ -529,7 +551,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
6f381c
         /* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also,
6f381c
          * always leave room for a terminating NUL we might need to add. */
6f381c
         limit = MIN(s->allocated - 1, s->server->line_max);
6f381c
-
6f381c
+        assert(s->length <= limit);
6f381c
         iovec = IOVEC_MAKE(s->buffer + s->length, limit - s->length);
6f381c
 
6f381c
         l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
6f381c
@@ -543,7 +565,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
6f381c
         cmsg_close_all(&msghdr);
6f381c
 
6f381c
         if (l == 0) {
6f381c
-                stdout_stream_scan(s, true);
6f381c
+                (void) stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_EOF, NULL);
6f381c
                 goto terminate;
6f381c
         }
6f381c
 
6f381c
@@ -562,22 +584,33 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
6f381c
          * in the meantime.
6f381c
          */
6f381c
         if (ucred && ucred->pid != s->ucred.pid) {
6f381c
-                /* force out any previously half-written lines from a
6f381c
-                 * different process, before we switch to the new ucred
6f381c
-                 * structure for everything we just added */
6f381c
-                r = stdout_stream_scan(s, true);
6f381c
+                /* Force out any previously half-written lines from a different process, before we switch to
6f381c
+                 * the new ucred structure for everything we just added */
6f381c
+                r = stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_PID_CHANGE, NULL);
6f381c
                 if (r < 0)
6f381c
                         goto terminate;
6f381c
 
6f381c
-                s->ucred = *ucred;
6f381c
                 s->context = client_context_release(s->server, s->context);
6f381c
+
6f381c
+                p = s->buffer + s->length;
6f381c
+        } else {
6f381c
+                p = s->buffer;
6f381c
+                l += s->length;
6f381c
         }
6f381c
 
6f381c
-        s->length += l;
6f381c
-        r = stdout_stream_scan(s, false);
6f381c
+        /* Always copy in the new credentials */
6f381c
+        if (ucred)
6f381c
+                s->ucred = *ucred;
6f381c
+
6f381c
+        r = stdout_stream_scan(s, p, l, _LINE_BREAK_INVALID, &consumed);
6f381c
         if (r < 0)
6f381c
                 goto terminate;
6f381c
 
6f381c
+        /* Move what wasn't consumed to the front of the buffer */
6f381c
+        assert(consumed <= (size_t) l);
6f381c
+        s->length = l - consumed;
6f381c
+        memmove(s->buffer, p + consumed, s->length);
6f381c
+
6f381c
         return 1;
6f381c
 
6f381c
 terminate: