[systemd-devel] [RFC PATCH] journal: allow callers to specify OBJECT_PID=

Zbigniew Jędrzejewski-Szmek zbyszek at in.waw.pl
Tue Jun 11 21:42:29 PDT 2013


When journald encounters a message with OBJECT_PID= set
coming from a priviledged process (UID==0), additional fields
will be added to the message:

OBJECT_UID=,
OBJECT_GID=,
OBJECT_COMM=,
OBJECT_EXE=,
OBJECT_CMDLINE=,
OBJECT_AUDIT_SESSION=,
OBJECT_AUDIT_LOGINUID=,
OBJECT_SYSTEMD_CGROUP=,
OBJECT_SYSTEMD_SESSION=,
OBJECT_SYSTEMD_OWNER_UID=,
OBJECT_SYSTEMD_UNIT= or OBJECT_SYSTEMD_USER_UNIT=.

This is for other logging daemons, like setroubleshoot, to be able to
augment their logs with data about the process.

https://bugzilla.redhat.com/show_bug.cgi?id=951627
---
Hi Daniel,
does this approach fit your purpose? Do you need more fields?

Actually the restriction that the sender is priviledged is not very
important, since we are just adding "normal" fields, that the process
could add itself. I'm keeping it because of the potential information
leak, where a process has access to the journal but is restricted
from /proc.

The reader side is more important. We need to figure out how
to show this information in journalctl and systemctl status, and
how to figure out if OBJECT_* fields can be trusted. But let's
decide that after we have the answer to the first two questions.

Zbyszek

PS. tl;dr:
$ sudo python -c "from systemd import journald; journal.send('goo goo', OBJECT_PID='1')"
$ journalctl -n1 -o verbose
...
        _UID=0
        _GID=0
        _MACHINE_ID=89b36a6f836cb8a001f613bd00000019
        _HOSTNAME=spora
        _TRANSPORT=journal
        _AUDIT_SESSION=2
        _AUDIT_LOGINUID=1001
        _EXE=/usr/bin/python2.7
        _SYSTEMD_CGROUP=/user/zbyszek/2
        _SELINUX_CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
        _COMM=python
        _CMDLINE=python
        CODE_FILE=<stdin>
        CODE_LINE=1
        CODE_FUNC=<module>
        SYSLOG_IDENTIFIER=python
        _BOOT_ID=dfa0f010b9864a5088fac7520b991adb
        MESSAGE=goo goo
        _PID=7588
        OBJECT_GID=0
        OBJECT_PID=1
        OBJECT_UID=0
        OBJECT_COMM=systemd
        OBJECT_EXE=/usr/lib/systemd/systemd
        OBJECT_CMDLINE=/usr/lib/systemd/systemd --switched-root --system --deserialize 23
        OBJECT_SYSTEMD_CGROUP=/system
        _SOURCE_REALTIME_TIMESTAMP=1371010406470566


 src/journal/journald-kmsg.c   |   2 +-
 src/journal/journald-native.c |  40 ++++++-----
 src/journal/journald-server.c | 163 +++++++++++++++++++++++++++++++++---------
 src/journal/journald-server.h |   3 +-
 src/journal/journald-stream.c |   2 +-
 src/journal/journald-syslog.c |   2 +-
 6 files changed, 157 insertions(+), 55 deletions(-)

diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 5fd87b8..21649d0 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -304,7 +304,7 @@ static void dev_kmsg_record(Server *s, char *p, size_t l) {
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority);
+        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0);
 
 finish:
         for (j = 0; j < z; j++)
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index ec9afa1..0f9af37 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -71,6 +71,10 @@ static bool valid_user_field(const char *p, size_t l) {
         return true;
 }
 
+static bool allow_object_pid(struct ucred *ucred) {
+        return ucred && ucred->uid == 0;
+}
+
 void server_process_native_message(
                 Server *s,
                 const void *buffer, size_t buffer_size,
@@ -79,11 +83,12 @@ void server_process_native_message(
                 const char *label, size_t label_len) {
 
         struct iovec *iovec = NULL;
-        unsigned n = 0, m = 0, j, tn = (unsigned) -1;
+        unsigned n = 0, j, tn = (unsigned) -1;
         const char *p;
-        size_t remaining;
+        size_t remaining, m = 0;
         int priority = LOG_INFO;
         char *identifier = NULL, *message = NULL;
+        pid_t object_pid = 0;
 
         assert(s);
         assert(buffer || buffer_size == 0);
@@ -104,7 +109,7 @@ void server_process_native_message(
 
                 if (e == p) {
                         /* Entry separator */
-                        server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
+                        server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
                         n = 0;
                         priority = LOG_INFO;
 
@@ -124,19 +129,10 @@ void server_process_native_message(
                 /* A property follows */
 
                 /* n received properties, +1 for _TRANSPORT */
-                if (n + 1 + N_IOVEC_META_FIELDS >= m) {
-                        struct iovec *c;
-                        unsigned u;
-
-                        u = MAX((n + 1 + N_IOVEC_META_FIELDS) * 2U, 4U);
-                        c = realloc(iovec, u * sizeof(struct iovec));
-                        if (!c) {
-                                log_oom();
-                                break;
-                        }
-
-                        iovec = c;
-                        m = u;
+                if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS +
+                                              !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
+                        log_oom();
+                        break;
                 }
 
                 q = memchr(p, '=', e - p);
@@ -191,6 +187,16 @@ void server_process_native_message(
                                                 free(message);
                                                 message = t;
                                         }
+                                } else if (l > strlen("OBJECT_PID=") &&
+                                           l < strlen("OBJECT_PID=")  + DECIMAL_STR_MAX(pid_t) &&
+                                           hasprefix(p, "OBJECT_PID=") &&
+                                           allow_object_pid(ucred)) {
+                                        char buf[DECIMAL_STR_MAX(pid_t)];
+                                        memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
+                                        char_array_0(buf);
+
+                                        /* ignore error */
+                                        parse_pid(buf, &object_pid);
                                 }
                         }
 
@@ -260,7 +266,7 @@ void server_process_native_message(
                         server_forward_console(s, priority, identifier, message, ucred);
         }
 
-        server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
+        server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
 
 finish:
         for (j = 0; j < n; j++)  {
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index a2b5ac7..f153f7e 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -488,24 +488,33 @@ static void dispatch_message_real(
                 struct ucred *ucred,
                 struct timeval *tv,
                 const char *label, size_t label_len,
-                const char *unit_id) {
+                const char *unit_id,
+                pid_t object_pid) {
 
-        char pid[sizeof("_PID=") + DECIMAL_STR_MAX(pid_t)],
+        char    pid[sizeof("_PID=") + DECIMAL_STR_MAX(pid_t)],
                 uid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)],
                 gid[sizeof("_GID=") + DECIMAL_STR_MAX(gid_t)],
                 owner_uid[sizeof("_SYSTEMD_OWNER_UID=") + DECIMAL_STR_MAX(uid_t)],
                 source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)],
                 boot_id[sizeof("_BOOT_ID=") + 32] = "_BOOT_ID=",
-                machine_id[sizeof("_MACHINE_ID=") + 32] = "_MACHINE_ID=";
-        char *comm, *exe, *cmdline, *cgroup, *session, *unit, *hostname;
+                machine_id[sizeof("_MACHINE_ID=") + 32] = "_MACHINE_ID=",
+                o_uid[sizeof("OBJECT_UID=") + DECIMAL_STR_MAX(uid_t)],
+                o_gid[sizeof("OBJECT_GID=") + DECIMAL_STR_MAX(gid_t)],
+                o_owner_uid[sizeof("OBJECT_SYSTEMD_OWNER_UID=") + DECIMAL_STR_MAX(uid_t)];
+        uid_t object_uid;
+        gid_t object_gid;
+
+        char *x;
         sd_id128_t id;
         int r;
         char *t, *c;
         uid_t realuid = 0, owner = 0, journal_uid;
         bool owner_valid = false;
 #ifdef HAVE_AUDIT
-        char audit_session[sizeof("_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)],
-                audit_loginuid[sizeof("_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)];
+        char    audit_session[sizeof("_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)],
+                audit_loginuid[sizeof("_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)],
+                o_audit_session[sizeof("OBJECT_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)],
+                o_audit_loginuid[sizeof("OBJECT_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)];
 
         uint32_t audit;
         uid_t loginuid;
@@ -514,7 +523,7 @@ static void dispatch_message_real(
         assert(s);
         assert(iovec);
         assert(n > 0);
-        assert(n + N_IOVEC_META_FIELDS <= m);
+        assert(n + N_IOVEC_META_FIELDS + (object_pid ? N_IOVEC_OBJECT_FIELDS : 0) <= m);
 
         if (ucred) {
                 realuid = ucred->uid;
@@ -530,23 +539,23 @@ static void dispatch_message_real(
 
                 r = get_process_comm(ucred->pid, &t);
                 if (r >= 0) {
-                        comm = strappenda("_COMM=", t);
+                        x = strappenda("_COMM=", t);
                         free(t);
-                        IOVEC_SET_STRING(iovec[n++], comm);
+                        IOVEC_SET_STRING(iovec[n++], x);
                 }
 
                 r = get_process_exe(ucred->pid, &t);
                 if (r >= 0) {
-                        exe = strappenda("_EXE=", t);
+                        x = strappenda("_EXE=", t);
                         free(t);
-                        IOVEC_SET_STRING(iovec[n++], exe);
+                        IOVEC_SET_STRING(iovec[n++], x);
                 }
 
                 r = get_process_cmdline(ucred->pid, 0, false, &t);
                 if (r >= 0) {
-                        cmdline = strappenda("_CMDLINE=", t);
+                        x = strappenda("_CMDLINE=", t);
                         free(t);
-                        IOVEC_SET_STRING(iovec[n++], cmdline);
+                        IOVEC_SET_STRING(iovec[n++], x);
                 }
 
 #ifdef HAVE_AUDIT
@@ -565,8 +574,10 @@ static void dispatch_message_real(
 
                 r = cg_pid_get_path_shifted(ucred->pid, NULL, &c);
                 if (r >= 0) {
-                        cgroup = strappenda("_SYSTEMD_CGROUP=", c);
-                        IOVEC_SET_STRING(iovec[n++], cgroup);
+                        char *session = NULL;
+
+                        x = strappenda("_SYSTEMD_CGROUP=", c);
+                        IOVEC_SET_STRING(iovec[n++], x);
 
                         r = cg_path_get_session(c, &t);
                         if (r >= 0) {
@@ -583,43 +594,126 @@ static void dispatch_message_real(
                         }
 
                         if (cg_path_get_unit(c, &t) >= 0) {
-                                unit = strappenda("_SYSTEMD_UNIT=", t);
+                                x = strappenda("_SYSTEMD_UNIT=", t);
                                 free(t);
                         } else if (cg_path_get_user_unit(c, &t) >= 0) {
-                                unit = strappenda("_SYSTEMD_USER_UNIT=", t);
+                                x = strappenda("_SYSTEMD_USER_UNIT=", t);
                                 free(t);
                         } else if (unit_id) {
                                 if (session)
-                                        unit = strappenda("_SYSTEMD_USER_UNIT=", unit_id);
+                                        x = strappenda("_SYSTEMD_USER_UNIT=", unit_id);
                                 else
-                                        unit = strappenda("_SYSTEMD_UNIT=", unit_id);
+                                        x = strappenda("_SYSTEMD_UNIT=", unit_id);
                         } else
-                                unit = NULL;
+                                x = NULL;
 
-                        if (unit)
-                                IOVEC_SET_STRING(iovec[n++], unit);
+                        if (x)
+                                IOVEC_SET_STRING(iovec[n++], x);
 
                         free(c);
                 }
 
 #ifdef HAVE_SELINUX
                 if (label) {
-                        char *selinux_context = alloca(sizeof("_SELINUX_CONTEXT=") + label_len);
+                        x = alloca(sizeof("_SELINUX_CONTEXT=") + label_len);
 
-                        *((char*) mempcpy(stpcpy(selinux_context, "_SELINUX_CONTEXT="), label, label_len)) = 0;
-                        IOVEC_SET_STRING(iovec[n++], selinux_context);
+                        *((char*) mempcpy(stpcpy(x, "_SELINUX_CONTEXT="), label, label_len)) = 0;
+                        IOVEC_SET_STRING(iovec[n++], x);
                 } else {
                         security_context_t con;
 
                         if (getpidcon(ucred->pid, &con) >= 0) {
-                                char *selinux_context = strappenda("_SELINUX_CONTEXT=", con);
+                                x = strappenda("_SELINUX_CONTEXT=", con);
 
                                 freecon(con);
-                                IOVEC_SET_STRING(iovec[n++], selinux_context);
+                                IOVEC_SET_STRING(iovec[n++], x);
                         }
                 }
 #endif
         }
+        assert(n <= m);
+
+        if (object_pid) {
+                r = get_process_uid(object_pid, &object_uid);
+                if (r >= 0) {
+                        sprintf(o_uid, "OBJECT_UID=%lu", (unsigned long) object_uid);
+                        IOVEC_SET_STRING(iovec[n++], o_uid);
+                }
+
+                r = get_process_gid(object_pid, &object_gid);
+                if (r >= 0) {
+                        sprintf(o_gid, "OBJECT_GID=%lu", (unsigned long) object_gid);
+                        IOVEC_SET_STRING(iovec[n++], o_gid);
+                }
+
+                r = get_process_comm(object_pid, &t);
+                if (r >= 0) {
+                        x = strappenda("OBJECT_COMM=", t);
+                        free(t);
+                        IOVEC_SET_STRING(iovec[n++], x);
+                }
+
+                r = get_process_exe(object_pid, &t);
+                if (r >= 0) {
+                        x = strappenda("OBJECT_EXE=", t);
+                        free(t);
+                        IOVEC_SET_STRING(iovec[n++], x);
+                }
+
+                r = get_process_cmdline(object_pid, 0, false, &t);
+                if (r >= 0) {
+                        x = strappenda("OBJECT_CMDLINE=", t);
+                        free(t);
+                        IOVEC_SET_STRING(iovec[n++], x);
+                }
+
+#ifdef HAVE_AUDIT
+                r = audit_session_from_pid(object_pid, &audit);
+                if (r >= 0) {
+                        sprintf(o_audit_session, "OBJECT_AUDIT_SESSION=%lu", (unsigned long) audit);
+                        IOVEC_SET_STRING(iovec[n++], o_audit_session);
+                }
+
+                r = audit_loginuid_from_pid(object_pid, &loginuid);
+                if (r >= 0) {
+                        sprintf(o_audit_loginuid, "OBJECT_AUDIT_LOGINUID=%lu", (unsigned long) loginuid);
+                        IOVEC_SET_STRING(iovec[n++], o_audit_loginuid);
+                }
+#endif
+
+                r = cg_pid_get_path_shifted(object_pid, NULL, &c);
+                if (r >= 0) {
+                        x = strappenda("OBJECT_SYSTEMD_CGROUP=", c);
+                        IOVEC_SET_STRING(iovec[n++], x);
+
+                        r = cg_path_get_session(c, &t);
+                        if (r >= 0) {
+                                x = strappenda("OBJECT_SYSTEMD_SESSION=", t);
+                                free(t);
+                                IOVEC_SET_STRING(iovec[n++], x);
+                        }
+
+                        if (cg_path_get_owner_uid(c, &owner) >= 0) {
+                                sprintf(o_owner_uid, "OBJECT_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner);
+                                IOVEC_SET_STRING(iovec[n++], o_owner_uid);
+                        }
+
+                        if (cg_path_get_unit(c, &t) >= 0) {
+                                x = strappenda("OBJECT_SYSTEMD_UNIT=", t);
+                                free(t);
+                        } else if (cg_path_get_user_unit(c, &t) >= 0) {
+                                x = strappenda("OBJECT_SYSTEMD_USER_UNIT=", t);
+                                free(t);
+                        } else
+                                x = NULL;
+
+                        if (x)
+                                IOVEC_SET_STRING(iovec[n++], x);
+
+                        free(c);
+                }
+        }
+        assert(n <= m);
 
         if (tv) {
                 sprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=%llu", (unsigned long long) timeval_load(tv));
@@ -631,21 +725,21 @@ static void dispatch_message_real(
          * anyway. However, we need this indexed, too. */
         r = sd_id128_get_boot(&id);
         if (r >= 0) {
-                sd_id128_to_string(id, boot_id + sizeof("_BOOT_ID=") - 1);
+                sd_id128_to_string(id, boot_id + strlen("_BOOT_ID="));
                 IOVEC_SET_STRING(iovec[n++], boot_id);
         }
 
         r = sd_id128_get_machine(&id);
         if (r >= 0) {
-                sd_id128_to_string(id, machine_id + sizeof("_MACHINE_ID=") - 1);
+                sd_id128_to_string(id, machine_id + strlen("_MACHINE_ID="));
                 IOVEC_SET_STRING(iovec[n++], machine_id);
         }
 
         t = gethostname_malloc();
         if (t) {
-                hostname = strappenda("_HOSTNAME=", t);
+                x = strappenda("_HOSTNAME=", t);
                 free(t);
-                IOVEC_SET_STRING(iovec[n++], hostname);
+                IOVEC_SET_STRING(iovec[n++], x);
         }
 
         assert(n <= m);
@@ -698,7 +792,7 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
         ucred.uid = getuid();
         ucred.gid = getgid();
 
-        dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL);
+        dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, 0);
 }
 
 void server_dispatch_message(
@@ -708,7 +802,8 @@ void server_dispatch_message(
                 struct timeval *tv,
                 const char *label, size_t label_len,
                 const char *unit_id,
-                int priority) {
+                int priority,
+                pid_t object_pid) {
 
         int rl, r;
         _cleanup_free_ char *path = NULL;
@@ -758,7 +853,7 @@ void server_dispatch_message(
                                       "Suppressed %u messages from %s", rl - 1, path);
 
 finish:
-        dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id);
+        dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, object_pid);
 }
 
 
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index 129f7e8..41f32ba 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -128,8 +128,9 @@ typedef struct Server {
 #define N_IOVEC_META_FIELDS 17
 #define N_IOVEC_KERNEL_FIELDS 64
 #define N_IOVEC_UDEV_FIELDS 32
+#define N_IOVEC_OBJECT_FIELDS 11
 
-void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority);
+void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid);
 void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_attr_(3,4);
 
 /* gperf lookup function */
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 3ce1c9a..e98fe94 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -127,7 +127,7 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
         }
 #endif
 
-        server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority);
+        server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
 
         free(message);
         free(syslog_priority);
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 4aeb9a3..7cbb346 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -400,7 +400,7 @@ void server_process_syslog_message(
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority);
+        server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority, 0);
 
         free(message);
         free(identifier);
-- 
1.8.2.562.g931e949



More information about the systemd-devel mailing list