kdbus: when uploading bus name policy, resolve users/groups out-of-process

It's not safe invoking NSS from PID 1, hence fork off worker processes
that upload the policy into the kernel for busnames.
This commit is contained in:
Lennart Poettering
2014-06-05 13:09:46 +02:00
parent 5331194c12
commit a4152e3fe2
11 changed files with 538 additions and 157 deletions
+94 -58
View File
@@ -1305,7 +1305,7 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) {
make->size += ALIGN8(n->size);
n = KDBUS_ITEM_NEXT(n);
sprintf(n->str, UID_FMT"-%s", 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);
@@ -1339,72 +1339,107 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) {
return fd;
}
static void bus_kernel_translate_policy(const BusNamePolicy *policy, struct kdbus_item *item) {
static int bus_kernel_translate_access(BusNamePolicyAccess access) {
assert(access >= 0);
assert(access < _BUSNAME_POLICY_ACCESS_MAX);
assert(policy);
assert(item);
switch (policy->type) {
case BUSNAME_POLICY_TYPE_USER:
item->policy_access.type = KDBUS_POLICY_ACCESS_USER;
item->policy_access.id = policy->uid;
break;
case BUSNAME_POLICY_TYPE_GROUP:
item->policy_access.type = KDBUS_POLICY_ACCESS_GROUP;
item->policy_access.id = policy->gid;
break;
case BUSNAME_POLICY_TYPE_WORLD:
item->policy_access.type = KDBUS_POLICY_ACCESS_WORLD;
break;
default:
assert_not_reached("Unknown policy type");
}
switch (policy->access) {
switch (access) {
case BUSNAME_POLICY_ACCESS_SEE:
item->policy_access.access = KDBUS_POLICY_SEE;
break;
return KDBUS_POLICY_SEE;
case BUSNAME_POLICY_ACCESS_TALK:
item->policy_access.access = KDBUS_POLICY_TALK;
break;
return KDBUS_POLICY_TALK;
case BUSNAME_POLICY_ACCESS_OWN:
item->policy_access.access = KDBUS_POLICY_OWN;
break;
return KDBUS_POLICY_OWN;
default:
assert_not_reached("Unknown policy access");
}
}
int bus_kernel_create_starter(const char *bus, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy) {
struct kdbus_cmd_hello *hello;
struct kdbus_item *n;
size_t policy_cnt = 0;
BusNamePolicy *po;
size_t size;
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 *p;
int fd;
assert(bus);
assert(name);
p = alloca(strlen("/dev/kdbus/") + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + strlen("/bus") + 1);
sprintf(p, "/dev/kdbus/"UID_FMT"-%s/bus", getuid(), bus);
sprintf(p, "/dev/kdbus/" UID_FMT "-%s/bus", getuid(), bus);
fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return -errno;
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));
@@ -1420,10 +1455,21 @@ int bus_kernel_create_starter(const char *bus, const char *name, bool activating
LIST_FOREACH(policy, po, policy) {
n->type = KDBUS_ITEM_POLICY_ACCESS;
n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
bus_kernel_translate_policy(po, n);
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) |
@@ -1431,23 +1477,17 @@ int bus_kernel_create_starter(const char *bus, const char *name, bool activating
hello->pool_size = KDBUS_POOL_SIZE;
hello->attach_flags = _KDBUS_ATTACH_ALL;
if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
safe_close(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) {
safe_close(fd);
hello->conn_flags > 0xFFFFFFFFULL)
return -ENOTSUP;
}
if (!bloom_validate_parameters((size_t) hello->bloom.size, (unsigned) hello->bloom.n_hash)) {
safe_close(fd);
if (!bloom_validate_parameters((size_t) hello->bloom.size, (unsigned) hello->bloom.n_hash))
return -ENOTSUP;
}
return fd;
}
@@ -1505,17 +1545,13 @@ int bus_kernel_create_domain(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(strlen("/dev/kdbus/") + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + strlen("/bus") + 1);
sprintf(p, "/dev/kdbus/"UID_FMT"-%s/bus", getuid(), bus);
fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
fd = bus_kernel_open_bus_fd(bus);
if (fd < 0)
return -errno;
return fd;
hello = alloca0(sizeof(struct kdbus_cmd_hello));
hello->size = sizeof(struct kdbus_cmd_hello);
+3 -1
View File
@@ -65,9 +65,11 @@ int bus_kernel_take_fd(sd_bus *b);
int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call);
int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority);
int bus_kernel_open_bus_fd(const char *bus);
int bus_kernel_make_starter(int fd, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy, BusNamePolicyAccess world_policy);
int bus_kernel_create_bus(const char *name, bool world, char **s);
int bus_kernel_create_domain(const char *name, char **s);
int bus_kernel_create_starter(const char *bus, const char *name, bool activating, bool accept_fd, BusNamePolicy *policy);
int bus_kernel_create_monitor(const char *bus);
int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated);