[systemd-commits] 3 commits - src/bus-proxyd src/core src/journal src/libsystemd-bus src/login src/shared src/udev

Lennart Poettering lennart at kemper.freedesktop.org
Tue Dec 24 07:22:17 PST 2013


 src/bus-proxyd/bus-proxyd.c      |   45 ---------------------------
 src/core/socket.c                |    7 ++--
 src/journal/journald-stream.c    |    5 +--
 src/libsystemd-bus/bus-control.c |   14 ++++++--
 src/libsystemd-bus/bus-kernel.c  |   21 +++++++++++--
 src/libsystemd-bus/bus-socket.c  |    6 ---
 src/login/pam-module.c           |    6 +--
 src/shared/socket-util.c         |    7 ++--
 src/shared/util.c                |   63 +++++++++++++++++++++++++++++++++++++++
 src/shared/util.h                |    4 ++
 src/udev/udev-ctrl.c             |   10 +++---
 11 files changed, 115 insertions(+), 73 deletions(-)

New commits:
commit ae98841e63a2624700db84ba44217f768b090d99
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Dec 24 16:21:59 2013 +0100

    util: don't accept an empty peer label as valid

diff --git a/src/shared/util.c b/src/shared/util.c
index 6b6722c..f491708 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -6172,6 +6172,11 @@ int getpeersec(int fd, char **ret) {
                 }
         }
 
+        if (isempty(s)) {
+                free(s);
+                return -ENOTSUP;
+        }
+
         *ret = s;
         return 0;
 }

commit 2dc9970bed3cee69e6746b110a649a9285dd6369
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Dec 24 16:20:47 2013 +0100

    bus: only accept kdbus creds if they are valid
    
    This allows userspace to fake kdbus creds via struct ucred in the proxy,
    without making the recieving side choke on the missing fields of the
    kdbus struct, more precisel pid_starttime and tid

diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c
index 1eed7b9..55986f3 100644
--- a/src/libsystemd-bus/bus-control.c
+++ b/src/libsystemd-bus/bus-control.c
@@ -407,17 +407,25 @@ static int bus_get_owner_kdbus(
                 switch (item->type) {
 
                 case KDBUS_ITEM_CREDS:
-                        m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID |
-                             SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask;
+                        m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID) & mask;
 
                         if (m) {
                                 c->uid = item->creds.uid;
                                 c->pid = item->creds.pid;
                                 c->gid = item->creds.gid;
+                                c->mask |= m;
+                        }
+
+                        if (mask & SD_BUS_CREDS_TID && item->creds.tid > 0) {
                                 c->tid = item->creds.tid;
+                                c->mask |= SD_BUS_CREDS_TID;
+                        }
+
+                        if (mask & SD_BUS_CREDS_PID_STARTTIME && item->creds.starttime > 0) {
                                 c->pid_starttime = item->creds.starttime;
-                                c->mask |= m;
+                                c->mask |= SD_BUS_CREDS_PID_STARTTIME;
                         }
+
                         break;
 
                 case KDBUS_ITEM_PID_COMM:
diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c
index 05544e1..19d97b7 100644
--- a/src/libsystemd-bus/bus-kernel.c
+++ b/src/libsystemd-bus/bus-kernel.c
@@ -793,12 +793,27 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
                 }
 
                 case KDBUS_ITEM_CREDS:
-                        m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
+                        /* UID/GID/PID are always valid */
                         m->creds.uid = d->creds.uid;
                         m->creds.gid = d->creds.gid;
                         m->creds.pid = d->creds.pid;
-                        m->creds.tid = d->creds.tid;
-                        m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID) & bus->creds_mask;
+                        m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID) & bus->creds_mask;
+
+                        /* The PID starttime/TID might be missing
+                         * however, when the data is faked by some
+                         * data bus proxy and it lacks that
+                         * information about the real client since
+                         * SO_PEERCRED is used for that */
+
+                        if (d->creds.starttime > 0) {
+                                m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
+                                m->creds.mask |= SD_BUS_CREDS_PID_STARTTIME & bus->creds_mask;
+                        }
+
+                        if (d->creds.tid > 0) {
+                                m->creds.tid = d->creds.tid;
+                                m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
+                        }
                         break;
 
                 case KDBUS_ITEM_TIMESTAMP:

commit eff05270986a13e7de93ae16311f654d3f7c166f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Dec 24 15:53:04 2013 +0100

    util: unify SO_PEERCRED/SO_PEERSEC invocations
    
    Introduce new call getpeercred() which internally just uses SO_PEERCRED
    but checks if the returned data is actually useful due to namespace
    quirks.

diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index b87dffe..60490d5 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -358,40 +358,6 @@ static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hell
         return 1;
 }
 
-static int getpeersec(int fd, char **ret) {
-        socklen_t n = 64;
-        char *s;
-        int r;
-
-        assert(fd >= 0);
-        assert(ret);
-
-        s = new0(char, n);
-        if (!s)
-                return -ENOMEM;
-
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
-        if (r < 0) {
-                free(s);
-
-                if (errno != ERANGE)
-                        return r;
-
-                s = new0(char, n);
-                if (!s)
-                        return -ENOMEM;
-
-                r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
-                if (r < 0) {
-                        free(s);
-                        return r;
-                }
-        }
-
-        *ret = s;
-        return 0;
-}
-
 int main(int argc, char *argv[]) {
 
         _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
@@ -427,16 +393,7 @@ int main(int argc, char *argv[]) {
                 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
 
         if (is_unix) {
-                socklen_t l = sizeof(ucred);
-
-                r = getsockopt(in_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
-                if (r < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                assert(l == sizeof(ucred));
-
+                getpeercred(in_fd, &ucred);
                 getpeersec(in_fd, &peersec);
         }
 
diff --git a/src/core/socket.c b/src/core/socket.c
index 31fc2a2..88599ca 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -671,10 +671,11 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
 
         case AF_UNIX: {
                 struct ucred ucred;
+                int k;
 
-                l = sizeof(ucred);
-                if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
-                        return -errno;
+                k = getpeercred(fd, &ucred);
+                if (k < 0)
+                        return k;
 
                 if (asprintf(&r,
                              "%u-%lu-%lu",
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index aba9054..c032ee4 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -354,7 +354,6 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
         Server *s = userdata;
         StdoutStream *stream;
         int fd, r;
-        socklen_t len;
 
         assert(s);
 
@@ -386,8 +385,8 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
 
         stream->fd = fd;
 
-        len = sizeof(stream->ucred);
-        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
+        r = getpeercred(fd, &stream->ucred);
+        if (r < 0) {
                 log_error("Failed to determine peer credentials: %m");
                 goto fail;
         }
diff --git a/src/libsystemd-bus/bus-socket.c b/src/libsystemd-bus/bus-socket.c
index 66924b2..0c4b6af 100644
--- a/src/libsystemd-bus/bus-socket.c
+++ b/src/libsystemd-bus/bus-socket.c
@@ -625,14 +625,10 @@ void bus_socket_setup(sd_bus *b) {
 }
 
 static void bus_get_peercred(sd_bus *b) {
-        socklen_t l;
-
         assert(b);
 
         /* Get the peer for socketpair() sockets */
-        l = sizeof(b->ucred);
-        if (getsockopt(b->input_fd, SOL_SOCKET, SO_PEERCRED, &b->ucred, &l) >= 0 && l >= sizeof(b->ucred))
-                b->ucred_valid = b->ucred.pid > 0;
+        b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0;
 }
 
 static int bus_socket_start_auth_client(sd_bus *b) {
diff --git a/src/login/pam-module.c b/src/login/pam-module.c
index 45428a0..89623aa 100644
--- a/src/login/pam-module.c
+++ b/src/login/pam-module.c
@@ -120,7 +120,6 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
         _cleanup_free_ char *p = NULL, *tty = NULL;
         _cleanup_close_ int fd = -1;
         struct ucred ucred;
-        socklen_t l;
         int v, r;
 
         assert(display);
@@ -144,10 +143,9 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
         if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
                 return -errno;
 
-        l = sizeof(ucred);
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
+        r = getpeercred(fd, &ucred);
         if (r < 0)
-                return -errno;
+                return r;
 
         r = get_ctty(ucred.pid, NULL, &tty);
         if (r < 0)
diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c
index 75c47d1..45ada7e 100644
--- a/src/shared/socket-util.c
+++ b/src/shared/socket-util.c
@@ -579,6 +579,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
 int getpeername_pretty(int fd, char **ret) {
         union sockaddr_union sa;
         socklen_t salen;
+        int r;
 
         assert(fd >= 0);
         assert(ret);
@@ -593,9 +594,9 @@ int getpeername_pretty(int fd, char **ret) {
                 /* UNIX connection sockets are anonymous, so let's use
                  * PID/UID as pretty credentials instead */
 
-                salen = sizeof(ucred);
-                if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &salen) < 0)
-                        return -errno;
+                r = getpeercred(fd, &ucred);
+                if (r < 0)
+                        return r;
 
                 if (asprintf(ret, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.pid) < 0)
                         return -ENOMEM;
diff --git a/src/shared/util.c b/src/shared/util.c
index 8d7cf53..6b6722c 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -6117,3 +6117,61 @@ bool pid_valid(pid_t pid) {
 
         return errno != ESRCH;
 }
+
+int getpeercred(int fd, struct ucred *ucred) {
+        socklen_t n = sizeof(struct ucred);
+        struct ucred u;
+        int r;
+
+        assert(fd >= 0);
+        assert(ucred);
+
+        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
+        if (r < 0)
+                return -errno;
+
+        if (n != sizeof(struct ucred))
+                return -EIO;
+
+        /* Check if the data is actually useful and not suppressed due
+         * to namespacing issues */
+        if (u.pid <= 0)
+                return -ENODATA;
+
+        *ucred = u;
+        return 0;
+}
+
+int getpeersec(int fd, char **ret) {
+        socklen_t n = 64;
+        char *s;
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        s = new0(char, n);
+        if (!s)
+                return -ENOMEM;
+
+        r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+        if (r < 0) {
+                free(s);
+
+                if (errno != ERANGE)
+                        return -errno;
+
+                s = new0(char, n);
+                if (!s)
+                        return -ENOMEM;
+
+                r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+                if (r < 0) {
+                        free(s);
+                        return -errno;
+                }
+        }
+
+        *ret = s;
+        return 0;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index 338d79c..57667ef 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -40,6 +40,7 @@
 #include <unistd.h>
 #include <locale.h>
 #include <mntent.h>
+#include <sys/socket.h>
 
 #include "macro.h"
 #include "time-util.h"
@@ -811,3 +812,6 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *root_fd);
 int namespace_enter(int pidns_fd, int mntns_fd, int root_fd);
 
 bool pid_valid(pid_t pid);
+
+int getpeercred(int fd, struct ucred *ucred);
+int getpeersec(int fd, char **ret);
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 4bb0cea..39d777e 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -181,10 +181,10 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
 {
         struct udev_ctrl_connection *conn;
         struct ucred ucred;
-        socklen_t slen;
         const int on = 1;
+        int r;
 
-        conn = calloc(1, sizeof(struct udev_ctrl_connection));
+        conn = new(struct udev_ctrl_connection, 1);
         if (conn == NULL)
                 return NULL;
         conn->refcount = 1;
@@ -198,9 +198,9 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
         }
 
         /* check peer credential of connection */
-        slen = sizeof(ucred);
-        if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
-                log_error("unable to receive credentials of ctrl connection: %m\n");
+        r = getpeercred(conn->sock, &ucred);
+        if (r < 0) {
+                log_error("unable to receive credentials of ctrl connection: %s", strerror(-r));
                 goto err;
         }
         if (ucred.uid > 0) {



More information about the systemd-commits mailing list