[systemd-commits] 3 commits - src/libsystemd-bus

Lennart Poettering lennart at kemper.freedesktop.org
Thu Mar 21 19:37:56 PDT 2013


 src/libsystemd-bus/bus-control.c      |   15 +++-
 src/libsystemd-bus/bus-internal.h     |    8 ++
 src/libsystemd-bus/bus-message.c      |   56 ++++++++++++++++-
 src/libsystemd-bus/bus-message.h      |    5 +
 src/libsystemd-bus/sd-bus.c           |  108 ++++++++++++++++++++++++++++------
 src/libsystemd-bus/sd-bus.h           |    4 -
 src/libsystemd-bus/test-bus-chat.c    |   13 +++-
 src/libsystemd-bus/test-bus-marshal.c |    2 
 8 files changed, 180 insertions(+), 31 deletions(-)

New commits:
commit 2571ead1a6d2747f85ecbc980285a22421e76e21
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Mar 22 03:36:58 2013 +0100

    bus: implicitly collect ucred/label information

diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h
index c5bd378..56514ae 100644
--- a/src/libsystemd-bus/bus-internal.h
+++ b/src/libsystemd-bus/bus-internal.h
@@ -62,6 +62,7 @@ struct sd_bus {
         int message_version;
         bool can_fds:1;
         bool sent_hello:1;
+        bool ucred_valid:1;
 
         void *rbuffer;
         size_t rbuffer_size;
@@ -101,6 +102,9 @@ struct sd_bus {
         size_t auth_size;
         char *auth_uid;
         usec_t auth_timeout;
+
+        struct ucred ucred;
+        char label[NAME_MAX];
 };
 
 static inline void bus_unrefp(sd_bus **b) {
diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c
index 74ea71e..01213e3 100644
--- a/src/libsystemd-bus/bus-message.c
+++ b/src/libsystemd-bus/bus-message.c
@@ -224,10 +224,16 @@ static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x)
         return 0;
 }
 
-int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret) {
+int bus_message_from_malloc(
+                void *buffer,
+                size_t length,
+                struct ucred *ucred,
+                const char *label,
+                sd_bus_message **ret) {
+
         sd_bus_message *m;
         struct bus_header *h;
-        size_t total, fs, bs;
+        size_t total, fs, bs, label_sz, a;
         int r;
 
         assert(buffer || length <= 0);
@@ -259,7 +265,13 @@ int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret) {
         if (length != total)
                 return -EBADMSG;
 
-        m = new0(sd_bus_message, 1);
+        if (label) {
+                label_sz = strlen(label);
+                a = ALIGN(sizeof(sd_bus_message)) + label_sz + 1;
+        } else
+                a = sizeof(sd_bus_message);
+
+        m = malloc0(a);
         if (!m)
                 return -ENOMEM;
 
@@ -270,6 +282,18 @@ int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret) {
         m->body = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN_TO(fs, 8);
         m->sealed = true;
 
+        if (ucred) {
+                m->uid = ucred->uid;
+                m->pid = ucred->pid;
+                m->gid = ucred->gid;
+                m->uid_valid = m->gid_valid = true;
+        }
+
+        if (label) {
+                m->label = (char*) m + ALIGN(sizeof(sd_bus_message));
+                memcpy(m->label, label, label_sz + 1);
+        }
+
         m->n_iovec = 1;
         m->iovec[0].iov_base = buffer;
         m->iovec[0].iov_len = length;
@@ -629,6 +653,13 @@ int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid) {
         return 0;
 }
 
+const char *sd_bus_message_get_label(sd_bus_message *m) {
+        if (!m)
+                return NULL;
+
+        return m->label;
+}
+
 int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member) {
         if (!m)
                 return -EINVAL;
diff --git a/src/libsystemd-bus/bus-message.h b/src/libsystemd-bus/bus-message.h
index ed1a4b8..b21fdf0 100644
--- a/src/libsystemd-bus/bus-message.h
+++ b/src/libsystemd-bus/bus-message.h
@@ -23,6 +23,7 @@
 
 #include <stdbool.h>
 #include <byteswap.h>
+#include <sys/socket.h>
 
 #include "macro.h"
 #include "sd-bus.h"
@@ -77,6 +78,8 @@ struct sd_bus_message {
         void *fields;
         void *body;
 
+        char *label;
+
         size_t rindex;
 
         uint32_t n_fds;
@@ -127,5 +130,5 @@ static inline void bus_message_unrefp(sd_bus_message **m) {
 int bus_message_seal(sd_bus_message *m, uint64_t serial);
 int bus_message_dump(sd_bus_message *m);
 int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz);
-int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret);
+int bus_message_from_malloc(void *buffer, size_t length, struct ucred *ucred, const char *label, sd_bus_message **ret);
 int bus_message_read_strv_extend(sd_bus_message *m, char ***l);
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 09ea01b..73774ba 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -29,6 +29,7 @@
 
 #include "util.h"
 #include "macro.h"
+#include "missing.h"
 
 #include "sd-bus.h"
 #include "bus-internal.h"
@@ -530,6 +531,24 @@ static int bus_read_auth(sd_bus *b) {
         return 1;
 }
 
+static int bus_setup_fd(sd_bus *b) {
+        int one;
+
+        assert(b);
+
+        /* Enable SO_PASSCRED + SO_PASSEC. We try this on any socket,
+         * just in case. This is actually irrelavant for */
+        one = 1;
+        setsockopt(b->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+        setsockopt(b->fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
+
+        /* Increase the buffers to a MB */
+        fd_inc_rcvbuf(b->fd, 1024*1024);
+        fd_inc_sndbuf(b->fd, 1024*1024);
+
+        return 0;
+}
+
 static int bus_start_auth(sd_bus *b) {
         static const char auth_prefix[] = "\0AUTH EXTERNAL ";
         static const char auth_suffix[] = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n";
@@ -578,8 +597,13 @@ static int bus_start_connect(sd_bus *b) {
                 b->fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
                 if (b->fd < 0) {
                         b->last_connect_error = errno;
-                        zero(b->sockaddr);
-                        continue;
+                        goto try_again;
+                }
+
+                r = bus_setup_fd(b);
+                if (r < 0) {
+                        b->last_connect_error = errno;
+                        goto try_again;
                 }
 
                 r = connect(b->fd, &b->sockaddr.sa, b->sockaddr_size);
@@ -588,13 +612,18 @@ static int bus_start_connect(sd_bus *b) {
                                 return 1;
 
                         b->last_connect_error = errno;
-                        close_nointr_nofail(b->fd);
-                        b->fd = -1;
-                        zero(b->sockaddr);
-                        continue;
+                        goto try_again;
                 }
 
                 return bus_start_auth(b);
+
+        try_again:
+                zero(b->sockaddr);
+
+                if (b->fd >= 0) {
+                        close_nointr_nofail(b->fd);
+                        b->fd = -1;
+                }
         }
 }
 
@@ -728,17 +757,29 @@ int sd_bus_open_fd(int fd, sd_bus **ret) {
                 return -ENOMEM;
 
         b->fd = fd;
-        fd_nonblock(b->fd, true);
+
+        r = fd_nonblock(b->fd, true);
+        if (r < 0)
+                goto fail;
+
         fd_cloexec(b->fd, true);
+        if (r < 0)
+                goto fail;
+
+        r = bus_setup_fd(b);
+        if (r < 0)
+                goto fail;
 
         r = bus_start_auth(b);
-        if (r < 0) {
-                bus_free(b);
-                return r;
-        }
+        if (r < 0)
+                goto fail;
 
         *ret = b;
         return 0;
+
+fail:
+                bus_free(b);
+        return r;
 }
 
 void sd_bus_close(sd_bus *bus) {
@@ -930,7 +971,9 @@ static int message_make(sd_bus *bus, size_t size, sd_bus_message **m) {
                 }
         }
 
-        r = bus_message_from_malloc(bus->rbuffer, size, &t);
+        r = bus_message_from_malloc(bus->rbuffer, size,
+                                    bus->ucred_valid ? &bus->ucred : NULL,
+                                    bus->label[0] ? bus->label : NULL, &t);
         if (r < 0) {
                 free(b);
                 return r;
@@ -950,6 +993,12 @@ static int message_read(sd_bus *bus, sd_bus_message **m) {
         size_t need;
         int r;
         void *b;
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
+                            CMSG_SPACE(NAME_MAX)]; /*selinux label */
+        } control;
+        struct cmsghdr *cmsg;
 
         assert(bus);
         assert(m);
@@ -975,12 +1024,34 @@ static int message_read(sd_bus *bus, sd_bus_message **m) {
         zero(mh);
         mh.msg_iov = &iov;
         mh.msg_iovlen = 1;
+        mh.msg_control = &control;
+        mh.msg_controllen = sizeof(control);
 
-        k = recvmsg(bus->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
+        k = recvmsg(bus->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
         if (k < 0)
                 return errno == EAGAIN ? 0 : -errno;
 
         bus->rbuffer_size += k;
+        bus->ucred_valid = false;
+        bus->label[0] = 0;
+
+        for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
+                if (cmsg->cmsg_level == SOL_SOCKET &&
+                    cmsg->cmsg_type == SCM_CREDENTIALS &&
+                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+
+                        memcpy(&bus->ucred, CMSG_DATA(cmsg), sizeof(struct ucred));
+                        bus->ucred_valid = true;
+
+                } else if (cmsg->cmsg_level == SOL_SOCKET &&
+                         cmsg->cmsg_type == SCM_SECURITY) {
+
+                        size_t l;
+                        l = cmsg->cmsg_len - CMSG_LEN(0);
+                        memcpy(&bus->label, CMSG_DATA(cmsg), l);
+                        bus->label[l] = 0;
+                }
+        }
 
         r = message_read_need(bus, &need);
         if (r < 0)
diff --git a/src/libsystemd-bus/sd-bus.h b/src/libsystemd-bus/sd-bus.h
index 60f2913..73710d1 100644
--- a/src/libsystemd-bus/sd-bus.h
+++ b/src/libsystemd-bus/sd-bus.h
@@ -106,6 +106,7 @@ int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid);
 int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid);
 int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid);
 int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid);
+const char *sd_bus_message_get_label(sd_bus_message *m);
 
 int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member);
 int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member);
diff --git a/src/libsystemd-bus/test-bus-chat.c b/src/libsystemd-bus/test-bus-chat.c
index 24a1943..23b00c7 100644
--- a/src/libsystemd-bus/test-bus-chat.c
+++ b/src/libsystemd-bus/test-bus-chat.c
@@ -83,6 +83,7 @@ static int server(sd_bus *bus) {
 
         while (!client1_gone || !client2_gone) {
                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+                pid_t pid = 0;
 
                 r = sd_bus_process(bus, &m);
                 if (r < 0) {
@@ -103,7 +104,8 @@ static int server(sd_bus *bus) {
                 if (!m)
                         continue;
 
-                log_info("Got message! %s", strna(sd_bus_message_get_member(m)));
+                sd_bus_message_get_pid(m, &pid);
+                log_info("Got message! member=%s pid=%lu label=%s", strna(sd_bus_message_get_member(m)), (unsigned long) pid, strna(sd_bus_message_get_label(m)));
                 /* bus_message_dump(m); */
                 /* sd_bus_message_rewind(m, true); */
 
diff --git a/src/libsystemd-bus/test-bus-marshal.c b/src/libsystemd-bus/test-bus-marshal.c
index d12c847..32bf44f 100644
--- a/src/libsystemd-bus/test-bus-marshal.c
+++ b/src/libsystemd-bus/test-bus-marshal.c
@@ -121,7 +121,7 @@ int main(int argc, char *argv[]) {
 
         m = sd_bus_message_unref(m);
 
-        r = bus_message_from_malloc(buffer, sz, &m);
+        r = bus_message_from_malloc(buffer, sz, NULL, NULL, &m);
         assert_se(r >= 0);
 
         bus_message_dump(m);

commit 20902f3ec8b9d3f8949b15dbd961d3eeb37e9b7b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Mar 22 03:34:29 2013 +0100

    bus: also finish connection before returning from sd_bus_get_unique_name()

diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c
index 9d242dc..06afaf3 100644
--- a/src/libsystemd-bus/bus-control.c
+++ b/src/libsystemd-bus/bus-control.c
@@ -28,11 +28,20 @@
 #include "bus-internal.h"
 #include "bus-message.h"
 
-const char *sd_bus_get_unique_name(sd_bus *bus) {
+int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
+        int r;
+
         if (!bus)
-                return NULL;
+                return -EINVAL;
+        if (!unique)
+                return -EINVAL;
 
-        return bus->unique_name;
+        r = bus_ensure_running(bus);
+        if (r < 0)
+                return r;
+
+        *unique = bus->unique_name;
+        return 0;
 }
 
 int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h
index d0b7b56..c5bd378 100644
--- a/src/libsystemd-bus/bus-internal.h
+++ b/src/libsystemd-bus/bus-internal.h
@@ -130,3 +130,5 @@ bool service_name_is_valid(const char *p);
 bool member_name_is_valid(const char *p);
 
 #define error_name_is_valid interface_name_is_valid
+
+int bus_ensure_running(sd_bus *bus);
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 9408806..09ea01b 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -35,7 +35,6 @@
 #include "bus-message.h"
 #include "bus-type.h"
 
-static int ensure_running(sd_bus *bus);
 static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
 
 static void bus_free(sd_bus *b) {
@@ -789,7 +788,7 @@ int sd_bus_can_send(sd_bus *bus, char type) {
                 return -EINVAL;
 
         if (type == SD_BUS_TYPE_UNIX_FD) {
-                r = ensure_running(bus);
+                r = bus_ensure_running(bus);
                 if (r < 0)
                         return r;
 
@@ -807,7 +806,7 @@ int sd_bus_get_peer(sd_bus *bus, sd_id128_t *peer) {
         if (!peer)
                 return -EINVAL;
 
-        r = ensure_running(bus);
+        r = bus_ensure_running(bus);
         if (r < 0)
                 return r;
 
@@ -1252,7 +1251,7 @@ int sd_bus_send_with_reply_cancel(sd_bus *bus, uint64_t serial) {
         return 1;
 }
 
-static int ensure_running(sd_bus *bus) {
+int bus_ensure_running(sd_bus *bus) {
         int r;
 
         assert(bus);
@@ -1300,7 +1299,7 @@ int sd_bus_send_with_reply_and_block(
         if (bus_error_is_dirty(error))
                 return -EINVAL;
 
-        r = ensure_running(bus);
+        r = bus_ensure_running(bus);
         if (r < 0)
                 return r;
 
@@ -1747,7 +1746,7 @@ int sd_bus_flush(sd_bus *bus) {
         if (bus->fd < 0)
                 return -ENOTCONN;
 
-        r = ensure_running(bus);
+        r = bus_ensure_running(bus);
         if (r < 0)
                 return r;
 
diff --git a/src/libsystemd-bus/sd-bus.h b/src/libsystemd-bus/sd-bus.h
index 8af1e85..60f2913 100644
--- a/src/libsystemd-bus/sd-bus.h
+++ b/src/libsystemd-bus/sd-bus.h
@@ -128,7 +128,7 @@ int sd_bus_message_rewind(sd_bus_message *m, int complete);
 
 /* Bus management */
 
-const char *sd_bus_get_unique_name(sd_bus *bus);
+int sd_bus_get_unique_name(sd_bus *bus, const char **unique);
 int sd_bus_request_name(sd_bus *bus, const char *name, int flags);
 int sd_bus_release_name(sd_bus *bus, const char *name);
 int sd_bus_list_names(sd_bus *bus, char ***l);
diff --git a/src/libsystemd-bus/test-bus-chat.c b/src/libsystemd-bus/test-bus-chat.c
index 5f533cc..24a1943 100644
--- a/src/libsystemd-bus/test-bus-chat.c
+++ b/src/libsystemd-bus/test-bus-chat.c
@@ -35,6 +35,7 @@ static int server_init(sd_bus **_bus) {
         sd_bus *bus = NULL;
         sd_id128_t id;
         int r;
+        const char *unique;
 
         assert(_bus);
 
@@ -50,9 +51,15 @@ static int server_init(sd_bus **_bus) {
                 goto fail;
         }
 
+        r = sd_bus_get_unique_name(bus, &unique);
+        if (r < 0) {
+                log_error("Failed to get unique name: %s", strerror(-r));
+                goto fail;
+        }
+
         log_info("Peer ID is " SD_ID128_FORMAT_STR ".", SD_ID128_FORMAT_VAL(id));
+        log_info("Unique ID: %s", unique);
         log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h'));
-        log_info("Unique ID: %s", strna(sd_bus_get_unique_name(bus)));
 
         r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
         if (r < 0) {

commit ed205a6bc53735392b46fde6820520a1d18d6ebd
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Mar 22 02:32:34 2013 +0100

    bus: when parsing enforce maximum container depth

diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h
index 3c2478e..d0b7b56 100644
--- a/src/libsystemd-bus/bus-internal.h
+++ b/src/libsystemd-bus/bus-internal.h
@@ -118,6 +118,8 @@ static inline void bus_unrefp(sd_bus **b) {
 #define BUS_MESSAGE_SIZE_MAX (64*1024*1024)
 #define BUS_AUTH_SIZE_MAX (64*1024)
 
+#define BUS_CONTAINER_DEPTH 128
+
 /* Defined by the specification as maximum size of an array in
  * bytes */
 #define BUS_ARRAY_MAX_SIZE 67108864
diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c
index ec98de3..74ea71e 100644
--- a/src/libsystemd-bus/bus-message.c
+++ b/src/libsystemd-bus/bus-message.c
@@ -1741,6 +1741,25 @@ int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *con
         if (!contents)
                 return -EINVAL;
 
+        /*
+         * We enforce a global limit on container depth, that is much
+         * higher than the 32 structs and 32 arrays the specification
+         * mandates. This is simpler to implement for us, and we need
+         * this only to ensure our container array doesn't grow
+         * without bounds. We are happy to return any data from a
+         * message as long as the data itself is valid, even if the
+         * overall message might be not.
+         *
+         * Note that the message signature is validated when
+         * parsing the headers, and that validation does check the
+         * 32/32 limit.
+         *
+         * Note that the specification defines no limits on the depth
+         * of stacked variants, but we do.
+         */
+        if (m->n_containers >= BUS_CONTAINER_DEPTH)
+                return -EBADMSG;
+
         w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
         if (!w)
                 return -ENOMEM;
diff --git a/src/libsystemd-bus/sd-bus.h b/src/libsystemd-bus/sd-bus.h
index adc7f8e..8af1e85 100644
--- a/src/libsystemd-bus/sd-bus.h
+++ b/src/libsystemd-bus/sd-bus.h
@@ -32,7 +32,6 @@
  * - make unix fd passing work
  * - add page donation logic
  * - api for appending/reading fixed arrays
- * - always verify container depth
  * - merge busctl into systemctl or so?
  * - add object handlers
  * - implicitly add stub introspection calls



More information about the systemd-commits mailing list