#include <fcntl.h>
#include <malloc.h>
#include <sys/mman.h>
+#include <sys/prctl.h>
#include "util.h"
#include "strv.h"
assert(m);
assert(m->sealed);
+ /* We put this together only once, if this message is reused
+ * we reuse the earlier-built version */
if (m->kdbus)
return 0;
case KDBUS_ITEM_TIMESTAMP:
m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
+ m->seqnum = d->timestamp.seqnum;
break;
case KDBUS_ITEM_PID_COMM:
goto fail;
break;
+ case KDBUS_ITEM_CONN_NAME:
+ m->creds.conn_name = d->str;
+ m->creds.mask |= SD_BUS_CREDS_CONNECTION_NAME & bus->creds_mask;
+ break;
+
case KDBUS_ITEM_FDS:
case KDBUS_ITEM_SECLABEL:
break;
int bus_kernel_take_fd(sd_bus *b) {
struct kdbus_cmd_hello *hello;
struct kdbus_item *item;
- size_t l = 0, sz;
+ _cleanup_free_ char *g = NULL;
+ const char *name;
+ size_t l = 0, m = 0, sz;
int r;
assert(b);
b->use_memfd = 1;
- sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items));
+ if (b->connection_name) {
+ g = sd_bus_label_escape(b->connection_name);
+ if (!g)
+ return -ENOMEM;
+
+ name = g;
+ } else {
+ char pr[17] = {};
+
+ /* If no name is explicitly set, we'll include a hint
+ * indicating the library implementation, a hint which
+ * kind of bus this is and the thread name */
+
+ assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
+
+ if (isempty(pr)) {
+ name = b->is_system ? "sd-system" :
+ b->is_user ? "sd-user" : "sd";
+ } else {
+ _cleanup_free_ char *e = NULL;
+
+ e = sd_bus_label_escape(pr);
+ if (!e)
+ return -ENOMEM;
+
+ g = strappend(b->is_system ? "sd-system-" :
+ b->is_user ? "sd-user-" : "sd-",
+ e);
+ if (!g)
+ return -ENOMEM;
+
+ name = g;
+ }
+
+ b->connection_name = sd_bus_label_unescape(name);
+ if (!b->connection_name)
+ return -ENOMEM;
+ }
+
+ m = strlen(name);
+
+ sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) +
+ ALIGN8(offsetof(struct kdbus_item, str) + m + 1);
if (b->fake_creds_valid)
- sz += ALIGN8(offsetof(struct kdbus_item, creds)) + sizeof(struct kdbus_creds);
+ sz += ALIGN8(offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds));
if (b->fake_label) {
l = strlen(b->fake_label);
item = hello->items;
+ item->size = offsetof(struct kdbus_item, str) + m + 1;
+ item->type = KDBUS_ITEM_CONN_NAME;
+ memcpy(item->str, name, m + 1);
+ item = KDBUS_ITEM_NEXT(item);
+
if (b->fake_creds_valid) {
item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
item->type = KDBUS_ITEM_CREDS;
if (b->fake_label) {
item->size = offsetof(struct kdbus_item, str) + l + 1;
+ item->type = KDBUS_ITEM_SECLABEL;
memcpy(item->str, b->fake_label, l+1);
}
return bus_kernel_take_fd(b);
}
-int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
+static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
+ uint64_t off;
+ struct kdbus_item *d;
+
+ assert(bus);
+ assert(k);
+
+ off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
+ ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
+
+ KDBUS_ITEM_FOREACH(d, k, items) {
+
+ if (d->type == KDBUS_ITEM_FDS)
+ close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
+ else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
+ close_nointr_nofail(d->memfd.fd);
+ }
+}
+
+int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call) {
int r;
assert(bus);
if (r < 0)
return r;
+ /* If this is a synchronous method call, then let's tell the
+ * kernel, so that it can pass CPU time/scheduling to the
+ * destination for the time, if it wants to. If we
+ * synchronously wait for the result anyway, we won't need CPU
+ * anyway. */
+ if (hint_sync_call)
+ m->kdbus->flags |= KDBUS_MSG_FLAGS_EXPECT_REPLY|KDBUS_MSG_FLAGS_SYNC_REPLY;
+
r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
if (r < 0) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
bus->rqueue[bus->rqueue_size++] = reply;
- return 0;
- }
-
- return 1;
-}
-
-static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
- uint64_t off;
- struct kdbus_item *d;
+ } else if (hint_sync_call) {
+ struct kdbus_msg *k;
- assert(bus);
- assert(k);
+ k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + m->kdbus->offset_reply);
+ assert(k);
- off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
- ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
+ if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
- KDBUS_ITEM_FOREACH(d, k, items) {
+ r = bus_kernel_make_message(bus, k);
+ if (r < 0) {
+ close_kdbus_msg(bus, k);
- if (d->type == KDBUS_ITEM_FDS)
- close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
- else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
- close_nointr_nofail(d->memfd.fd);
+ /* Anybody can send us invalid messages, let's just drop them. */
+ if (r == -EBADMSG || r == -EPROTOTYPE)
+ log_debug("Ignoring invalid message: %s", strerror(-r));
+ else
+ return r;
+ }
+ } else {
+ log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type);
+ close_kdbus_msg(bus, k);
+ }
}
+
+ return 1;
}
static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
return -errno;
}
- k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.offset);
+ k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.offset);
if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
r = bus_kernel_make_message(bus, k);
} else if (k->payload_type == KDBUS_PAYLOAD_KERNEL)
r = bus_kernel_translate_message(bus, k);
- else
+ else {
+ log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type);
r = 0;
+ }
if (r <= 0)
close_kdbus_msg(bus, k);
assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
if (bus->n_memfd_cache <= 0) {
- struct kdbus_cmd_memfd_make cmd = {
- .size = sizeof(struct kdbus_cmd_memfd_make),
- };
+ _cleanup_free_ char *g = NULL;
+ struct kdbus_cmd_memfd_make *cmd;
+ struct kdbus_item *item;
+ size_t l, sz;
int r;
assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
- r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &cmd);
+ assert(bus->connection_name);
+
+ g = sd_bus_label_escape(bus->connection_name);
+ if (!g)
+ return -ENOMEM;
+
+ l = strlen(g);
+ sz = ALIGN8(offsetof(struct kdbus_cmd_memfd_make, items)) +
+ ALIGN8(offsetof(struct kdbus_item, str)) +
+ l + 1;
+ cmd = alloca0(sz);
+ cmd->size = sz;
+
+ item = cmd->items;
+ item->size = ALIGN8(offsetof(struct kdbus_item, str)) + l + 1;
+ item->type = KDBUS_ITEM_MEMFD_NAME;
+ memcpy(item->str, g, l + 1);
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, cmd);
if (r < 0)
return -errno;
*address = NULL;
*mapped = 0;
*allocated = 0;
- return cmd.fd;
+ return cmd->fd;
}
c = &bus->memfd_cache[--bus->n_memfd_cache];
if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
m |= KDBUS_ATTACH_NAMES;
+ if (mask & SD_BUS_CREDS_CONNECTION_NAME)
+ m |= KDBUS_ATTACH_CONN_NAME;
+
*kdbus_mask = m;
return 0;
}