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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user