X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-bus%2Fbus-kernel.c;h=8b961c38eb2ffe6e72c444ba99609a1e823fa909;hp=833ea5574ddbde16fc180ace3973815287e3ec95;hb=f1e3bee216b9eac1d5b00415617cb2ff5e894c10;hpb=8d1db1d154c1134c9bf92b202ef198cc79979ea8 diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index 833ea5574..8b961c38e 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -36,6 +36,7 @@ #include "bus-kernel.h" #include "bus-bloom.h" #include "bus-util.h" +#include "bus-label.h" #include "cgroup-util.h" #define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t)) @@ -101,20 +102,21 @@ static void append_destination(struct kdbus_item **d, const char *s, size_t leng *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); } -static void* append_bloom(struct kdbus_item **d, size_t length) { - void *r; +static struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) { + struct kdbus_item *i; assert(d); - *d = ALIGN8_PTR(*d); + i = ALIGN8_PTR(*d); - (*d)->size = offsetof(struct kdbus_item, data) + length; - (*d)->type = KDBUS_ITEM_BLOOM; - r = (*d)->data; + i->size = offsetof(struct kdbus_item, bloom_filter) + + offsetof(struct kdbus_bloom_filter, data) + + length; + i->type = KDBUS_ITEM_BLOOM_FILTER; - *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); + *d = (struct kdbus_item *) ((uint8_t*) i + i->size); - return r; + return &i->bloom_filter; } static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) { @@ -130,25 +132,28 @@ static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) { *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); } -static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) { +static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) { + void *data; unsigned i; int r; assert(m); assert(bloom); - memset(bloom, 0, BLOOM_SIZE); + data = bloom->data; + memzero(data, m->bus->bloom_size); + bloom->generation = 0; - bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type)); + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type)); if (m->interface) - bloom_add_pair(bloom, "interface", m->interface); + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface); if (m->member) - bloom_add_pair(bloom, "member", m->member); + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member); if (m->path) { - bloom_add_pair(bloom, "path", m->path); - bloom_add_pair(bloom, "path-slash-prefix", m->path); - bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/'); + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", m->path); + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path); + bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/'); } r = sd_bus_message_rewind(m, true); @@ -183,12 +188,12 @@ static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) { } *e = 0; - bloom_add_pair(bloom, buf, t); + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t); strcpy(e, "-dot-prefix"); - bloom_add_prefixes(bloom, buf, t, '.'); + bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '.'); strcpy(e, "-slash-prefix"); - bloom_add_prefixes(bloom, buf, t, '/'); + bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '/'); } return 0; @@ -231,7 +236,9 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)); /* Add space for bloom filter */ - sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE); + sz += ALIGN8(offsetof(struct kdbus_item, bloom_filter) + + offsetof(struct kdbus_bloom_filter, data) + + m->bus->bloom_size); /* Add in well-known destination header */ if (well_known) { @@ -250,7 +257,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { } m->free_kdbus = true; - memset(m->kdbus, 0, sz); + memzero(m->kdbus, sz); m->kdbus->flags = ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) | @@ -259,7 +266,8 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { well_known ? 0 : m->destination ? unique : KDBUS_DST_ID_BROADCAST; m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS; - m->kdbus->cookie = m->header->serial; + m->kdbus->cookie = (uint64_t) m->header->serial; + m->kdbus->priority = m->priority; if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) m->kdbus->cookie_reply = m->reply_cookie; @@ -292,8 +300,8 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { continue; } - /* Otherwise let's send a vector to the actual data, - * for that we need to map it first. */ + /* Otherwise, let's send a vector to the actual data. + * For that, we need to map it first. */ r = bus_body_part_map(part); if (r < 0) goto fail; @@ -302,10 +310,10 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { } if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) { - void *p; + struct kdbus_bloom_filter *bloom; - p = append_bloom(&d, BLOOM_SIZE); - r = bus_message_setup_bloom(m, p); + bloom = append_bloom(&d, m->bus->bloom_size); + r = bus_message_setup_bloom(m, bloom); if (r < 0) goto fail; } @@ -500,9 +508,13 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { break; 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; + + if (bus->attach_flags & KDBUS_ATTACH_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: @@ -568,6 +580,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; @@ -642,7 +659,7 @@ int bus_kernel_take_fd(sd_bus *b) { b->use_memfd = 1; if (b->connection_name) { - g = sd_bus_label_escape(b->connection_name); + g = bus_label_escape(b->connection_name); if (!g) return -ENOMEM; @@ -662,7 +679,7 @@ int bus_kernel_take_fd(sd_bus *b) { } else { _cleanup_free_ char *e = NULL; - e = sd_bus_label_escape(pr); + e = bus_label_escape(pr); if (!e) return -ENOMEM; @@ -675,7 +692,7 @@ int bus_kernel_take_fd(sd_bus *b) { name = g; } - b->connection_name = sd_bus_label_unescape(name); + b->connection_name = bus_label_unescape(name); if (!b->connection_name) return -ENOMEM; } @@ -738,9 +755,12 @@ int bus_kernel_take_fd(sd_bus *b) { hello->conn_flags > 0xFFFFFFFFULL) return -ENOTSUP; - if (hello->bloom_size != BLOOM_SIZE) + if (!bloom_validate_parameters((size_t) hello->bloom.size, (unsigned) hello->bloom.n_hash)) return -ENOTSUP; + b->bloom_size = (size_t) hello->bloom.size; + b->bloom_n_hash = (unsigned) hello->bloom.n_hash; + if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0) return -ENOMEM; @@ -791,7 +811,7 @@ static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *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); + safe_close(d->memfd.fd); } } @@ -901,10 +921,10 @@ static int push_name_owner_changed(sd_bus *bus, const char *name, const char *ol r = sd_bus_message_new_signal( bus, + &m, "/org/freedesktop/DBus", "org.freedesktop.DBus", - "NameOwnerChanged", - &m); + "NameOwnerChanged"); if (r < 0) return r; @@ -1029,7 +1049,7 @@ static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) { return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found); } -int bus_kernel_read_message(sd_bus *bus) { +int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) { struct kdbus_cmd_recv recv = {}; struct kdbus_msg *k; int r; @@ -1040,6 +1060,11 @@ int bus_kernel_read_message(sd_bus *bus) { if (r < 0) return r; + if (hint_priority) { + recv.flags |= KDBUS_RECV_USE_PRIORITY; + recv.priority = priority; + } + r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &recv); if (r < 0) { if (errno == EAGAIN) @@ -1095,7 +1120,7 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al assert(bus->connection_name); - g = sd_bus_label_escape(bus->connection_name); + g = bus_label_escape(bus->connection_name); if (!g) return -ENOMEM; @@ -1140,7 +1165,7 @@ static void close_and_munmap(int fd, void *address, size_t size) { if (size > 0) assert_se(munmap(address, PAGE_ALIGN(size)) >= 0); - close_nointr_nofail(fd); + safe_close(fd); } void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated) { @@ -1240,6 +1265,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; } @@ -1264,29 +1292,35 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) { make->size = offsetof(struct kdbus_cmd_make, items); n = make->items; - n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t); - n->type = KDBUS_ITEM_BLOOM_SIZE; - n->data64[0] = BLOOM_SIZE; - assert_cc(BLOOM_SIZE % 8 == 0); + n->size = offsetof(struct kdbus_item, bloom_parameter) + + sizeof(struct kdbus_bloom_parameter); + n->type = KDBUS_ITEM_BLOOM_PARAMETER; + + n->bloom_parameter.size = DEFAULT_BLOOM_SIZE; + n->bloom_parameter.n_hash = DEFAULT_BLOOM_N_HASH; + + assert_cc(DEFAULT_BLOOM_SIZE > 0); + assert_cc(DEFAULT_BLOOM_N_HASH > 0); + make->size += ALIGN8(n->size); n = KDBUS_ITEM_NEXT(n); - sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name); + sprintf(n->str, UID_FMT "-%s", getuid(), name); n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1; n->type = KDBUS_ITEM_MAKE_NAME; make->size += ALIGN8(n->size); - make->flags = KDBUS_MAKE_POLICY_OPEN | (world ? KDBUS_MAKE_ACCESS_WORLD : 0); + make->flags = world ? KDBUS_MAKE_ACCESS_WORLD : 0; if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) { - close_nointr_nofail(fd); + safe_close(fd); return -errno; } /* The higher 32bit of the flags field are considered * 'incompatible flags'. Refuse them all for now. */ if (make->flags > 0xFFFFFFFFULL) { - close_nointr_nofail(fd); + safe_close(fd); return -ENOTSUP; } @@ -1295,7 +1329,7 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) { p = strjoin("/dev/kdbus/", n->str, "/bus", NULL); if (!p) { - close_nointr_nofail(fd); + safe_close(fd); return -ENOMEM; } @@ -1305,57 +1339,169 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) { return fd; } -int bus_kernel_create_starter(const char *bus, const char *name) { - struct kdbus_cmd_hello *hello; - struct kdbus_item *n; +static int bus_kernel_translate_access(BusNamePolicyAccess access) { + assert(access >= 0); + assert(access < _BUSNAME_POLICY_ACCESS_MAX); + + switch (access) { + + case BUSNAME_POLICY_ACCESS_SEE: + return KDBUS_POLICY_SEE; + + case BUSNAME_POLICY_ACCESS_TALK: + return KDBUS_POLICY_TALK; + + case BUSNAME_POLICY_ACCESS_OWN: + return KDBUS_POLICY_OWN; + + default: + assert_not_reached("Unknown policy access"); + } +} + +static int bus_kernel_translate_policy(const BusNamePolicy *policy, struct kdbus_item *item) { + int r; + + assert(policy); + assert(item); + + switch (policy->type) { + + case BUSNAME_POLICY_TYPE_USER: { + const char *user = policy->name; + uid_t uid; + + r = get_user_creds(&user, &uid, NULL, NULL, NULL); + if (r < 0) + return r; + + item->policy_access.type = KDBUS_POLICY_ACCESS_USER; + item->policy_access.id = uid; + break; + } + + case BUSNAME_POLICY_TYPE_GROUP: { + const char *group = policy->name; + gid_t gid; + + r = get_group_creds(&group, &gid); + if (r < 0) + return r; + + item->policy_access.type = KDBUS_POLICY_ACCESS_GROUP; + item->policy_access.id = gid; + break; + } + + default: + assert_not_reached("Unknown policy type"); + } + + item->policy_access.access = bus_kernel_translate_access(policy->access); + + return 0; +} + +int bus_kernel_open_bus_fd(const char *bus, char **path) { char *p; int fd; + size_t len; - assert(bus); - assert(name); + len = strlen("/dev/kdbus/") + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + strlen("/bus") + 1; - p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus")); - sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus); + if (path) { + p = malloc(len); + if (!p) + return -ENOMEM; + *path = p; + } else + p = alloca(len); + sprintf(p, "/dev/kdbus/" UID_FMT "-%s/bus", getuid(), bus); fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC); if (fd < 0) return -errno; - hello = alloca0(ALIGN8(offsetof(struct kdbus_cmd_hello, items) + - offsetof(struct kdbus_item, str) + - strlen(name) + 1)); + return fd; +} + +int bus_kernel_make_starter( + int fd, + const char *name, + bool activating, + bool accept_fd, + BusNamePolicy *policy, + BusNamePolicyAccess world_policy) { + + struct kdbus_cmd_hello *hello; + struct kdbus_item *n; + size_t policy_cnt = 0; + BusNamePolicy *po; + size_t size; + int r; + + assert(fd >= 0); + assert(name); + + LIST_FOREACH(policy, po, policy) + policy_cnt++; + + if (world_policy >= 0) + policy_cnt++; + + size = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) + + ALIGN8(offsetof(struct kdbus_item, str) + strlen(name) + 1) + + policy_cnt * ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access)); + + hello = alloca0(size); n = hello->items; strcpy(n->str, name); n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1; n->type = KDBUS_ITEM_NAME; + n = KDBUS_ITEM_NEXT(n); - hello->size = ALIGN8(offsetof(struct kdbus_cmd_hello, items) + n->size); - hello->conn_flags = KDBUS_HELLO_ACTIVATOR; + LIST_FOREACH(policy, po, policy) { + n->type = KDBUS_ITEM_POLICY_ACCESS; + n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access); + + r = bus_kernel_translate_policy(po, n); + if (r < 0) + return r; + + n = KDBUS_ITEM_NEXT(n); + } + + if (world_policy >= 0) { + n->type = KDBUS_ITEM_POLICY_ACCESS; + n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access); + n->policy_access.type = KDBUS_POLICY_ACCESS_WORLD; + n->policy_access.access = bus_kernel_translate_access(world_policy); + } + + hello->size = size; + hello->conn_flags = + (activating ? KDBUS_HELLO_ACTIVATOR : KDBUS_HELLO_POLICY_HOLDER) | + (accept_fd ? KDBUS_HELLO_ACCEPT_FD : 0); hello->pool_size = KDBUS_POOL_SIZE; + hello->attach_flags = _KDBUS_ATTACH_ALL; - if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) { - close_nointr_nofail(fd); + if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) return -errno; - } /* 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) { - close_nointr_nofail(fd); + hello->conn_flags > 0xFFFFFFFFULL) return -ENOTSUP; - } - if (hello->bloom_size != BLOOM_SIZE) { - close_nointr_nofail(fd); + if (!bloom_validate_parameters((size_t) hello->bloom.size, (unsigned) hello->bloom.n_hash)) return -ENOTSUP; - } return fd; } -int bus_kernel_create_namespace(const char *name, char **s) { +int bus_kernel_create_domain(const char *name, char **s) { struct kdbus_cmd_make *make; struct kdbus_item *n; int fd; @@ -1377,26 +1523,26 @@ int bus_kernel_create_namespace(const char *name, char **s) { n->type = KDBUS_ITEM_MAKE_NAME; make->size = ALIGN8(offsetof(struct kdbus_cmd_make, items) + n->size); - make->flags = KDBUS_MAKE_POLICY_OPEN | KDBUS_MAKE_ACCESS_WORLD; + make->flags = KDBUS_MAKE_ACCESS_WORLD; - if (ioctl(fd, KDBUS_CMD_NS_MAKE, make) < 0) { - close_nointr_nofail(fd); + if (ioctl(fd, KDBUS_CMD_DOMAIN_MAKE, make) < 0) { + safe_close(fd); return -errno; } /* The higher 32bit of the flags field are considered * 'incompatible flags'. Refuse them all for now. */ if (make->flags > 0xFFFFFFFFULL) { - close_nointr_nofail(fd); + safe_close(fd); return -ENOTSUP; } if (s) { char *p; - p = strappend("/dev/kdbus/ns/", name); + p = strappend("/dev/kdbus/domain/", name); if (!p) { - close_nointr_nofail(fd); + safe_close(fd); return -ENOMEM; } @@ -1408,17 +1554,13 @@ int bus_kernel_create_namespace(const char *name, char **s) { int bus_kernel_create_monitor(const char *bus) { struct kdbus_cmd_hello *hello; - char *p; int fd; assert(bus); - p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus")); - sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus); - - fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC); + fd = bus_kernel_open_bus_fd(bus, NULL); if (fd < 0) - return -errno; + return fd; hello = alloca0(sizeof(struct kdbus_cmd_hello)); hello->size = sizeof(struct kdbus_cmd_hello); @@ -1426,7 +1568,7 @@ int bus_kernel_create_monitor(const char *bus) { hello->pool_size = KDBUS_POOL_SIZE; if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) { - close_nointr_nofail(fd); + safe_close(fd); return -errno; } @@ -1434,7 +1576,7 @@ int bus_kernel_create_monitor(const char *bus) { * 'incompatible flags'. Refuse them all for now. */ if (hello->bus_flags > 0xFFFFFFFFULL || hello->conn_flags > 0xFFFFFFFFULL) { - close_nointr_nofail(fd); + safe_close(fd); return -ENOTSUP; } @@ -1450,3 +1592,16 @@ int bus_kernel_try_close(sd_bus *bus) { return 0; } + +int bus_kernel_drop_one(int fd) { + struct kdbus_cmd_recv recv = { + .flags = KDBUS_RECV_DROP + }; + + assert(fd >= 0); + + if (ioctl(fd, KDBUS_CMD_MSG_RECV, &recv) < 0) + return -errno; + + return 0; +}