From: Luca Boccassi Date: Fri, 19 Sep 2025 23:49:42 +0000 (+0100) Subject: machined: allow privileged users to register other users machines X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6815a48f085e5951eb39eafbd47560dbe62d5ca0;p=thirdparty%2Fsystemd.git 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 119d332d9c2cf1974b235c8d9e4e3ad821cf436a --- diff --git a/src/machine/machine-varlink.c b/src/machine/machine-varlink.c index 7c4c05865b8..a73f81b6f72 100644 --- a/src/machine/machine-varlink.c +++ b/src/machine/machine-varlink.c @@ -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; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index f5315b97630..3591bbca2e5 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -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;