chiark / gitweb /
gpt-auto-generator: skip nonexistent devices
[elogind.git] / src / libsystemd-bus / bus-kernel.c
index 369eac468b21454a68e141e92042b8b874cd5467..e8f4c581105f6a3b29166ec8876e48e2147abf98 100644 (file)
@@ -35,6 +35,7 @@
 #include "bus-kernel.h"
 #include "bus-bloom.h"
 #include "bus-util.h"
+#include "cgroup-util.h"
 
 #define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
 
@@ -174,10 +175,10 @@ static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
 
                 e = stpcpy(buf, "arg");
                 if (i < 10)
-                        *(e++) = '0' + i;
+                        *(e++) = '0' + (char) i;
                 else {
-                        *(e++) = '0' + (i / 10);
-                        *(e++) = '0' + (i % 10);
+                        *(e++) = '0' + (char) (i / 10);
+                        *(e++) = '0' + (char) (i % 10);
                 }
 
                 *e = 0;
@@ -257,7 +258,10 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
         m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS;
         m->kdbus->cookie = m->header->serial;
 
-        m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
+        if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+                m->kdbus->cookie_reply = m->reply_cookie;
+        else
+                m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
 
         d = m->kdbus->items;
 
@@ -317,7 +321,9 @@ fail:
 }
 
 int bus_kernel_take_fd(sd_bus *b) {
-        struct kdbus_cmd_hello hello;
+        struct kdbus_cmd_hello *hello;
+        struct kdbus_item *item;
+        size_t l = 0, sz;
         int r;
 
         assert(b);
@@ -327,13 +333,38 @@ int bus_kernel_take_fd(sd_bus *b) {
 
         b->use_memfd = 1;
 
-        zero(hello);
-        hello.size = sizeof(hello);
-        hello.conn_flags = b->hello_flags;
-        hello.attach_flags = b->attach_flags;
-        hello.pool_size = KDBUS_POOL_SIZE;
+        sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items));
+
+        if (b->fake_creds_valid)
+                sz += ALIGN8(offsetof(struct kdbus_item, creds)) + sizeof(struct kdbus_creds);
+
+        if (b->fake_label) {
+                l = strlen(b->fake_label);
+                sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
+        }
+
+        hello = alloca0(sz);
+        hello->size = sz;
+        hello->conn_flags = b->hello_flags;
+        hello->attach_flags = b->attach_flags;
+        hello->pool_size = KDBUS_POOL_SIZE;
+
+        item = hello->items;
 
-        r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
+        if (b->fake_creds_valid) {
+                item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
+                item->type = KDBUS_ITEM_CREDS;
+                item->creds = b->fake_creds;
+
+                item = KDBUS_ITEM_NEXT(item);
+        }
+
+        if (b->fake_label) {
+                item->size = offsetof(struct kdbus_item, str) + l + 1;
+                memcpy(item->str, b->fake_label, l+1);
+        }
+
+        r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
         if (r < 0)
                 return -errno;
 
@@ -347,26 +378,26 @@ int bus_kernel_take_fd(sd_bus *b) {
 
         /* The higher 32bit of both flags fields are considered
          * 'incompatible flags'. Refuse them all for now. */
-        if (hello.bus_flags > 0xFFFFFFFFULL ||
-            hello.conn_flags > 0xFFFFFFFFULL)
+        if (hello->bus_flags > 0xFFFFFFFFULL ||
+            hello->conn_flags > 0xFFFFFFFFULL)
                 return -ENOTSUP;
 
-        if (hello.bloom_size != BLOOM_SIZE)
+        if (hello->bloom_size != BLOOM_SIZE)
                 return -ENOTSUP;
 
-        if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
+        if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
                 return -ENOMEM;
 
-        b->unique_id = hello.id;
+        b->unique_id = hello->id;
 
         b->is_kernel = true;
         b->bus_client = true;
-        b->can_fds = !!(hello.conn_flags & KDBUS_HELLO_ACCEPT_FD);
+        b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD);
         b->message_version = 2;
         b->message_endian = BUS_NATIVE_ENDIAN;
 
         /* the kernel told us the UUID of the underlying bus */
-        memcpy(b->server_id.bytes, hello.id128, sizeof(b->server_id.bytes));
+        memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes));
 
         return bus_start_running(b);
 }
@@ -439,7 +470,7 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
 
                 r = bus_message_new_synthetic_error(
                                 bus,
-                                BUS_MESSAGE_SERIAL(m),
+                                BUS_MESSAGE_COOKIE(m),
                                 &error,
                                 &reply);
 
@@ -693,6 +724,13 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
         if (r < 0)
                 return r;
 
+        /* The well-known names list is different from the other
+        credentials. If we asked for it, but nothing is there, this
+        means that the list of well-known names is simply empty, not
+        that we lack any data */
+
+        m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
+
         KDBUS_ITEM_FOREACH(d, k, items) {
                 size_t l;
 
@@ -759,12 +797,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;
-                        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;
+                        /* UID/GID/PID are always valid */
+                        m->creds.uid = (uid_t) d->creds.uid;
+                        m->creds.gid = (gid_t) d->creds.gid;
+                        m->creds.pid = (pid_t) d->creds.pid;
+                        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 = (pid_t) d->creds.tid;
+                                m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
+                        }
                         break;
 
                 case KDBUS_ITEM_TIMESTAMP:
@@ -796,11 +849,20 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
                 case KDBUS_ITEM_CGROUP:
                         m->creds.cgroup = d->str;
                         m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask;
+
+                        if (!bus->cgroup_root) {
+                                r = cg_get_root_path(&bus->cgroup_root);
+                                if (r < 0)
+                                        goto fail;
+                        }
+
+                        m->creds.cgroup_root = bus->cgroup_root;
+
                         break;
 
                 case KDBUS_ITEM_AUDIT:
-                        m->creds.audit_session_id = d->audit.sessionid;
-                        m->creds.audit_login_uid = d->audit.loginuid;
+                        m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
+                        m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
                         m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
                         break;
 
@@ -811,14 +873,19 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
                         break;
 
                 case KDBUS_ITEM_DST_NAME:
+                        if (!service_name_is_valid(d->str))
+                                return -EBADMSG;
+
                         destination = d->str;
                         break;
 
                 case KDBUS_ITEM_NAME:
+                        if (!service_name_is_valid(d->name.name))
+                                return -EBADMSG;
+
                         r = strv_extend(&m->creds.well_known_names, d->name.name);
                         if (r < 0)
                                 goto fail;
-                        m->creds.mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES & bus->creds_mask;
                         break;
 
                 case KDBUS_ITEM_FDS:
@@ -836,21 +903,21 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
 
         /* Override information from the user header with data from the kernel */
         if (k->src_id == KDBUS_SRC_ID_KERNEL)
-                m->sender = "org.freedesktop.DBus";
+                m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
         else {
                 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
                 m->sender = m->creds.unique_name = m->sender_buffer;
-                m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & bus->creds_mask;
         }
 
-        if (!m->destination) {
-                if (destination)
-                        m->destination = destination;
-                else if (k->dst_id != KDBUS_DST_ID_NAME &&
-                         k->dst_id != KDBUS_DST_ID_BROADCAST) {
-                        snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
-                        m->destination = m->destination_buffer;
-                }
+        if (destination)
+                m->destination = destination;
+        else if (k->dst_id == KDBUS_DST_ID_BROADCAST)
+                m->destination = NULL;
+        else if (k->dst_id == KDBUS_DST_ID_NAME)
+                m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */
+        else {
+                snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
+                m->destination = m->destination_buffer;
         }
 
         /* We take possession of the kmsg struct now */
@@ -1070,7 +1137,7 @@ int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) {
         return 0;
 }
 
-int bus_kernel_create_bus(const char *name, char **s) {
+int bus_kernel_create_bus(const char *name, bool world, char **s) {
         struct kdbus_cmd_make *make;
         struct kdbus_item *n;
         int fd;
@@ -1102,7 +1169,7 @@ int bus_kernel_create_bus(const char *name, char **s) {
         n->type = KDBUS_ITEM_MAKE_NAME;
         make->size += ALIGN8(n->size);
 
-        make->flags = KDBUS_MAKE_POLICY_OPEN;
+        make->flags = KDBUS_MAKE_POLICY_OPEN | (world ? KDBUS_MAKE_ACCESS_WORLD : 0);
 
         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
                 close_nointr_nofail(fd);
@@ -1266,3 +1333,13 @@ int bus_kernel_create_monitor(const char *bus) {
 
         return fd;
 }
+
+int bus_kernel_try_close(sd_bus *bus) {
+        assert(bus);
+        assert(bus->is_kernel);
+
+        if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE) < 0)
+                return -errno;
+
+        return 0;
+}