machined: allow privileged users to register other users machines

If a user is authenticated by polkit as admin then it should be
able to manage any resource on the system.

Follow-up for 119d332d9c
This commit is contained in:
Luca Boccassi
2025-09-20 00:49:42 +01:00
parent 5ce1786227
commit 6815a48f08
2 changed files with 34 additions and 25 deletions

View File

@@ -126,6 +126,7 @@ static int machine_cid(const char *name, sd_json_variant *variant, sd_json_dispa
int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
_cleanup_(machine_freep) Machine *machine = NULL;
bool sender_is_admin = false;
int r;
static const sd_json_dispatch_field dispatch_table[] = {
@@ -160,13 +161,16 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink
return sd_varlink_error_invalid_parameter_name(link, "class");
if (manager->runtime_scope != RUNTIME_SCOPE_USER) {
r = varlink_verify_polkit_async(
r = varlink_verify_polkit_async_full(
link,
manager->system_bus,
machine->allocate_unit ? "org.freedesktop.machine1.create-machine" : "org.freedesktop.machine1.register-machine",
(const char**) STRV_MAKE("name", machine->name,
"class", machine_class_to_string(machine->class)),
&manager->polkit_registry);
/* good_user= */ UID_INVALID,
/* flags= */ 0,
&manager->polkit_registry,
&sender_is_admin);
if (r <= 0)
return r;
}
@@ -196,7 +200,7 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink
/* In system scope, ensure an unprivileged user cannot claim any process they don't
* control as their own machine. In user scope the varlink socket is already
* protected by $XDG_RUNTIME_DIR permissions. */
if (manager->runtime_scope != RUNTIME_SCOPE_USER && machine->uid != 0) {
if (manager->runtime_scope != RUNTIME_SCOPE_USER && machine->uid != 0 && !sender_is_admin) {
r = process_is_owned_by_uid(&machine->leader, machine->uid);
if (r < 0)
return r;

View File

@@ -279,12 +279,33 @@ static int machine_add_from_params(
/* Ensure an unprivileged user cannot claim any process they don't control as their own machine */
switch (manager->runtime_scope) {
case RUNTIME_SCOPE_SYSTEM:
/* In system mode root may register anything */
if (uid == 0)
case RUNTIME_SCOPE_SYSTEM: {
const char *details[] = {
"name", name,
"class", machine_class_to_string(c),
NULL
};
bool sender_is_admin = false;
r = bus_verify_polkit_async_full(
message,
polkit_action,
details,
/* good_user= */ UID_INVALID,
/* flags= */ 0,
&manager->polkit_registry,
&sender_is_admin,
error);
if (r < 0)
return r;
if (r == 0)
return 0; /* Will call us back */
/* In system mode root/admin may register anything */
if (uid == 0 || sender_is_admin)
break;
/* And non-root may only register things if they own the userns */
/* And non-root/admin may only register things if they own the userns */
r = process_is_owned_by_uid(leader_pidref, uid);
if (r < 0)
return r;
@@ -292,7 +313,8 @@ static int machine_add_from_params(
break;
/* Nothing else may */
return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users");
return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only privileged users may register machines for other users");
}
case RUNTIME_SCOPE_USER:
/* In user mode the user owning our instance may register anything. */
@@ -306,23 +328,6 @@ static int machine_add_from_params(
assert_not_reached();
}
if (manager->runtime_scope != RUNTIME_SCOPE_USER) {
const char *details[] = {
"name", name,
"class", machine_class_to_string(c),
NULL
};
r = bus_verify_polkit_async(
message,
polkit_action,
details,
&manager->polkit_registry,
error);
if (r <= 0)
return r; /* 0 means Polkit will call us back, see method_create_machine() */
}
r = manager_add_machine(manager, name, &m);
if (r < 0)
return r;