X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-bus%2Fbus-kernel.c;h=95efbbeeb863fe8b0ac558021cd052d474822c81;hb=cccb0b2cdbd25e90ae92d2d5b107125cb1ca3433;hp=f85b4d5676ff252c0642e0dbd2082dc23d196727;hpb=607553f9306286fdccf0b356bc3d1087adfe21c4;p=elogind.git diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index f85b4d567..95efbbeeb 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "util.h" #include "strv.h" @@ -206,6 +207,8 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { 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; @@ -499,6 +502,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { 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: @@ -564,6 +568,11 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { 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; @@ -625,7 +634,9 @@ fail: 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); @@ -635,10 +646,52 @@ int bus_kernel_take_fd(sd_bus *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); @@ -653,6 +706,11 @@ int bus_kernel_take_fd(sd_bus *b) { 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; @@ -663,6 +721,7 @@ int bus_kernel_take_fd(sd_bus *b) { 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); } @@ -722,7 +781,26 @@ int bus_kernel_connect(sd_bus *b) { 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); @@ -738,6 +816,14 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) { 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; @@ -785,29 +871,31 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) { 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) { @@ -964,8 +1052,8 @@ int bus_kernel_read_message(sd_bus *bus) { 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); @@ -977,8 +1065,10 @@ int bus_kernel_read_message(sd_bus *bus) { } 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); @@ -1000,21 +1090,40 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al 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]; @@ -1136,6 +1245,9 @@ int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) { 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; }