[systemd-commits] 2 commits - src/journal src/util.c

Lennart Poettering lennart at kemper.freedesktop.org
Mon Mar 12 18:35:58 PDT 2012


 src/journal/journald.c |  106 ++++++++++++++++++++++++++++++++++++-------------
 src/util.c             |   54 +++++++++++++++++-------
 2 files changed, 118 insertions(+), 42 deletions(-)

New commits:
commit b19be9eb9e231ccf350e0e051b687fc425c61904
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Mar 13 02:29:27 2012 +0100

    util: add brute-force fallback for close_all_fds()
    
    If /proc is not available (i.e. in chroot envs) let's fall back to brute
    forcing our way through the fd table.
    
    https://bugzilla.redhat.com/show_bug.cgi?id=784921

diff --git a/src/util.c b/src/util.c
index 3a855c1..73481ab 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2207,13 +2207,47 @@ int fd_cloexec(int fd, bool cloexec) {
         return 0;
 }
 
+static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
+        unsigned i;
+
+        assert(n_fdset == 0 || fdset);
+
+        for (i = 0; i < n_fdset; i++)
+                if (fdset[i] == fd)
+                        return true;
+
+        return false;
+}
+
 int close_all_fds(const int except[], unsigned n_except) {
         DIR *d;
         struct dirent *de;
         int r = 0;
 
-        if (!(d = opendir("/proc/self/fd")))
-                return -errno;
+        assert(n_except == 0 || except);
+
+        d = opendir("/proc/self/fd");
+        if (!d) {
+                int fd;
+                struct rlimit rl;
+
+                /* When /proc isn't available (for example in chroots)
+                 * the fallback is brute forcing through the fd
+                 * table */
+
+                assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
+                for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
+
+                        if (fd_in_set(fd, except, n_except))
+                                continue;
+
+                        if (close_nointr(fd) < 0)
+                                if (errno != EBADF && r == 0)
+                                        r = -errno;
+                }
+
+                return r;
+        }
 
         while ((de = readdir(d))) {
                 int fd = -1;
@@ -2231,20 +2265,8 @@ int close_all_fds(const int except[], unsigned n_except) {
                 if (fd == dirfd(d))
                         continue;
 
-                if (except) {
-                        bool found;
-                        unsigned i;
-
-                        found = false;
-                        for (i = 0; i < n_except; i++)
-                                if (except[i] == fd) {
-                                        found = true;
-                                        break;
-                                }
-
-                        if (found)
-                                continue;
-                }
+                if (fd_in_set(fd, except, n_except))
+                        continue;
 
                 if (close_nointr(fd) < 0) {
                         /* Valgrind has its own FD and doesn't want to have it closed */

commit 7f2c63cbf47c89ec56f50469f6551df473dd65d8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Mar 13 02:21:59 2012 +0100

    journald: use SCM_SECURITY to race-freely determine peer SELinux label
    
    https://bugzilla.redhat.com/show_bug.cgi?id=798760

diff --git a/src/journal/journald.c b/src/journal/journald.c
index 375f5aa..e9c00b4 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -45,6 +45,7 @@
 #include "conf-parser.h"
 #include "journald.h"
 #include "virt.h"
+#include "missing.h"
 
 #ifdef HAVE_ACL
 #include <sys/acl.h>
@@ -87,6 +88,9 @@ struct StdoutStream {
         int fd;
 
         struct ucred ucred;
+#ifdef HAVE_SELINUX
+        security_context_t security_context;
+#endif
 
         char *identifier;
         int priority;
@@ -430,10 +434,12 @@ static char *shortened_cgroup_path(pid_t pid) {
         return path;
 }
 
-static void dispatch_message_real(Server *s,
-                             struct iovec *iovec, unsigned n, unsigned m,
-                             struct ucred *ucred,
-                             struct timeval *tv) {
+static void dispatch_message_real(
+                Server *s,
+                struct iovec *iovec, unsigned n, unsigned m,
+                struct ucred *ucred,
+                struct timeval *tv,
+                const char *label, size_t label_len) {
 
         char *pid = NULL, *uid = NULL, *gid = NULL,
                 *source_time = NULL, *boot_id = NULL, *machine_id = NULL,
@@ -458,9 +464,6 @@ static void dispatch_message_real(Server *s,
         if (ucred) {
                 uint32_t audit;
                 uid_t owner;
-#ifdef HAVE_SELINUX
-                security_context_t con;
-#endif
 
                 realuid = ucred->uid;
 
@@ -540,12 +543,24 @@ static void dispatch_message_real(Server *s,
                                 IOVEC_SET_STRING(iovec[n++], owner_uid);
 
 #ifdef HAVE_SELINUX
-                if (getpidcon(ucred->pid, &con) >= 0) {
-                        selinux_context = strappend("_SELINUX_CONTEXT=", con);
-                        if (selinux_context)
+                if (label) {
+                        selinux_context = malloc(sizeof("_SELINUX_CONTEXT=") + label_len);
+                        if (selinux_context) {
+                                memcpy(selinux_context, "_SELINUX_CONTEXT=", sizeof("_SELINUX_CONTEXT=")-1);
+                                memcpy(selinux_context+sizeof("_SELINUX_CONTEXT=")-1, label, label_len);
+                                selinux_context[sizeof("_SELINUX_CONTEXT=")-1+label_len] = 0;
                                 IOVEC_SET_STRING(iovec[n++], selinux_context);
+                        }
+                } else {
+                        security_context_t con;
+
+                        if (getpidcon(ucred->pid, &con) >= 0) {
+                                selinux_context = strappend("_SELINUX_CONTEXT=", con);
+                                if (selinux_context)
+                                        IOVEC_SET_STRING(iovec[n++], selinux_context);
 
-                        freecon(con);
+                                freecon(con);
+                        }
                 }
 #endif
         }
@@ -652,13 +667,14 @@ static void 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);
+        dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0);
 }
 
 static void dispatch_message(Server *s,
                              struct iovec *iovec, unsigned n, unsigned m,
                              struct ucred *ucred,
                              struct timeval *tv,
+                             const char *label, size_t label_len,
                              int priority) {
         int rl;
         char *path = NULL, *c;
@@ -706,7 +722,7 @@ static void dispatch_message(Server *s,
         free(path);
 
 finish:
-        dispatch_message_real(s, iovec, n, m, ucred, tv);
+        dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len);
 }
 
 static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
@@ -1006,7 +1022,7 @@ static void read_identifier(const char **buf, char **identifier, char **pid) {
         *buf += strspn(*buf, WHITESPACE);
 }
 
-static void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv) {
+static void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len) {
         char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
         struct iovec iovec[N_IOVEC_META_FIELDS + 6];
         unsigned n = 0;
@@ -1054,7 +1070,7 @@ static void process_syslog_message(Server *s, const char *buf, struct ucred *ucr
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, priority);
+        dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, priority);
 
         free(message);
         free(identifier);
@@ -1099,7 +1115,13 @@ static bool valid_user_field(const char *p, size_t l) {
         return true;
 }
 
-static void process_native_message(Server *s, const void *buffer, size_t buffer_size, struct ucred *ucred, struct timeval *tv) {
+static void process_native_message(
+                Server *s,
+                const void *buffer, size_t buffer_size,
+                struct ucred *ucred,
+                struct timeval *tv,
+                const char *label, size_t label_len) {
+
         struct iovec *iovec = NULL;
         unsigned n = 0, m = 0, j, tn = (unsigned) -1;
         const char *p;
@@ -1126,7 +1148,7 @@ static void process_native_message(Server *s, const void *buffer, size_t buffer_
 
                 if (e == p) {
                         /* Entry separator */
-                        dispatch_message(s, iovec, n, m, ucred, tv, priority);
+                        dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, priority);
                         n = 0;
                         priority = LOG_INFO;
 
@@ -1275,7 +1297,7 @@ static void process_native_message(Server *s, const void *buffer, size_t buffer_
                         forward_console(s, identifier, message, ucred);
         }
 
-        dispatch_message(s, iovec, n, m, ucred, tv, priority);
+        dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, priority);
 
 finish:
         for (j = 0; j < n; j++)  {
@@ -1291,7 +1313,13 @@ finish:
         free(message);
 }
 
-static void process_native_file(Server *s, int fd, struct ucred *ucred, struct timeval *tv) {
+static void process_native_file(
+                Server *s,
+                int fd,
+                struct ucred *ucred,
+                struct timeval *tv,
+                const char *label, size_t label_len) {
+
         struct stat st;
         void *p;
         ssize_t n;
@@ -1332,7 +1360,7 @@ static void process_native_file(Server *s, int fd, struct ucred *ucred, struct t
         if (n < 0)
                 log_error("Failed to read file, ignoring: %s", strerror(-n));
         else if (n > 0)
-                process_native_message(s, p, n, ucred, tv);
+                process_native_message(s, p, n, ucred, tv, label, label_len);
 
         free(p);
 }
@@ -1342,6 +1370,8 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
         char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL;
         unsigned n = 0;
         int priority;
+        char *label = NULL;
+        size_t label_len = 0;
 
         assert(s);
         assert(p);
@@ -1382,7 +1412,14 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, priority);
+#ifdef HAVE_SELINUX
+        if (s->security_context) {
+                label = (char*) s->security_context;
+                label_len = strlen((char*) s->security_context);
+        }
+#endif
+
+        dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, priority);
 
         free(message);
         free(syslog_priority);
@@ -1576,6 +1613,11 @@ static void stdout_stream_free(StdoutStream *s) {
                 close_nointr_nofail(s->fd);
         }
 
+#ifdef HAVE_SELINUX
+        if (s->security_context)
+                freecon(s->security_context);
+#endif
+
         free(s->identifier);
         free(s);
 }
@@ -1619,6 +1661,11 @@ static int stdout_stream_new(Server *s) {
                 goto fail;
         }
 
+#ifdef HAVE_SELINUX
+        if (getpeercon(fd, &stream->security_context) < 0)
+                log_error("Failed to determine peer security context.");
+#endif
+
         if (shutdown(fd, SHUT_WR) < 0) {
                 log_error("Failed to shutdown writing side of socket: %m");
                 r = -errno;
@@ -1753,7 +1800,7 @@ static void proc_kmsg_line(Server *s, const char *p) {
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
 
-        dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, priority);
+        dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, priority);
 
         free(message);
         free(syslog_priority);
@@ -2079,11 +2126,14 @@ static int process_event(Server *s, struct epoll_event *ev) {
                         struct ucred *ucred = NULL;
                         struct timeval *tv = NULL;
                         struct cmsghdr *cmsg;
+                        char *label = NULL;
+                        size_t label_len = 0;
                         union {
                                 struct cmsghdr cmsghdr;
                                 uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
                                             CMSG_SPACE(sizeof(struct timeval)) +
-                                            CMSG_SPACE(sizeof(int))];
+                                            CMSG_SPACE(sizeof(int)) +
+                                            CMSG_SPACE(LINE_MAX)]; /* selinux label */
                         } control;
                         ssize_t n;
                         int v;
@@ -2139,6 +2189,10 @@ static int process_event(Server *s, struct epoll_event *ev) {
                                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
                                         ucred = (struct ucred*) CMSG_DATA(cmsg);
                                 else if (cmsg->cmsg_level == SOL_SOCKET &&
+                                         cmsg->cmsg_type == SCM_SECURITY) {
+                                        label = (char*) CMSG_DATA(cmsg);
+                                        label_len = cmsg->cmsg_len - CMSG_LEN(0);
+                                } else if (cmsg->cmsg_level == SOL_SOCKET &&
                                          cmsg->cmsg_type == SO_TIMESTAMP &&
                                          cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
                                         tv = (struct timeval*) CMSG_DATA(cmsg);
@@ -2159,15 +2213,15 @@ static int process_event(Server *s, struct epoll_event *ev) {
                                         else
                                                 s->buffer[n] = 0;
 
-                                        process_syslog_message(s, strstrip(s->buffer), ucred, tv);
+                                        process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
                                 } else if (n_fds > 0)
                                         log_warning("Got file descriptors via syslog socket. Ignoring.");
 
                         } else {
                                 if (n > 0 && n_fds == 0)
-                                        process_native_message(s, s->buffer, n, ucred, tv);
+                                        process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
                                 else if (n == 0 && n_fds == 1)
-                                        process_native_file(s, fds[0], ucred, tv);
+                                        process_native_file(s, fds[0], ucred, tv, label, label_len);
                                 else if (n_fds > 0)
                                         log_warning("Got too many file descriptors via native socket. Ignoring.");
                         }



More information about the systemd-commits mailing list