X-Git-Url: https://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=b46cada6489d8f93253b68355452d18dcb1033f2;hb=8f077bf94e129fa1b6f0159e3140c4326f1066cf;hpb=ff975efb2e88dcd5221a2f0d76c4c87e85b821a8 diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index b46cada64..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)) @@ -140,19 +141,19 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter assert(bloom); data = bloom->data; - memset(data, 0, BLOOM_SIZE); + memzero(data, m->bus->bloom_size); bloom->generation = 0; - bloom_add_pair(data, "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(data, "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(data, "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(data, "path", m->path); - bloom_add_pair(data, "path-slash-prefix", m->path); - bloom_add_prefixes(data, "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); @@ -187,12 +188,12 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter } *e = 0; - bloom_add_pair(data, buf, t); + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t); strcpy(e, "-dot-prefix"); - bloom_add_prefixes(data, buf, t, '.'); + bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '.'); strcpy(e, "-slash-prefix"); - bloom_add_prefixes(data, buf, t, '/'); + bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '/'); } return 0; @@ -237,7 +238,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { /* Add space for bloom filter */ sz += ALIGN8(offsetof(struct kdbus_item, bloom_filter) + offsetof(struct kdbus_bloom_filter, data) + - BLOOM_SIZE); + m->bus->bloom_size); /* Add in well-known destination header */ if (well_known) { @@ -256,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) | @@ -265,7 +266,7 @@ 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) @@ -299,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; @@ -311,7 +312,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) { struct kdbus_bloom_filter *bloom; - bloom = append_bloom(&d, BLOOM_SIZE); + bloom = append_bloom(&d, m->bus->bloom_size); r = bus_message_setup_bloom(m, bloom); if (r < 0) goto fail; @@ -658,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; @@ -678,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; @@ -691,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; } @@ -754,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; @@ -807,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); } } @@ -917,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; @@ -1116,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; @@ -1161,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) { @@ -1291,28 +1295,32 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) { n->size = offsetof(struct kdbus_item, bloom_parameter) + sizeof(struct kdbus_bloom_parameter); n->type = KDBUS_ITEM_BLOOM_PARAMETER; - n->bloom_parameter.size = BLOOM_SIZE; - n->bloom_parameter.n_hash = 1; - assert_cc(BLOOM_SIZE % 8 == 0); + + 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; } @@ -1321,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; } @@ -1331,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; @@ -1403,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; } @@ -1434,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); @@ -1452,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; } @@ -1460,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; }