From 814db2ae79054d7382e69fb36a4240fdd138e5f8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Aug 2025 14:14:18 +0200 Subject: [PATCH] nspawn: register containers with both the system-wide and the per-user machined instance Let's make sure each container run by unpriv users is known by both instances. Making it known by the host instance ensures it is resovlable by nss-myhostname (and various other tools), but making it known by the per-user instance means the user can fully manage it on their own. This simplifies the code a bit too, i.e. we always allocate a scope ourselves now, and just register it, instead of letting machined do that under some circumstances. THere's little value in that and it simplifies things for us quite a bit. --- src/nspawn/nspawn-register.c | 168 ++++++----------------------------- src/nspawn/nspawn-register.h | 13 +-- src/nspawn/nspawn.c | 79 +++++++++------- 3 files changed, 74 insertions(+), 186 deletions(-) diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index 516f67c7600..04031adcc5a 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -131,30 +131,25 @@ static int can_set_coredump_receive(sd_bus *bus) { return r >= 0; } -static int create_or_register_machine_ex( +static int register_machine_ex( sd_bus *bus, const char *machine_name, const PidRef *pid, const char *directory, sd_id128_t uuid, int local_ifindex, - const char *slice, - CustomMount *mounts, - unsigned n_mounts, - int kill_signal, - char **properties, - sd_bus_message *properties_message, const char *service, - StartMode start_mode, - sd_bus_error *error, - bool keep_unit) { + sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; + assert(bus); + assert(machine_name); + assert(service); assert(error); - r = bus_message_new_method_call(bus, &m, bus_machine_mgr, keep_unit ? "RegisterMachineEx" : "CreateMachineEx"); + r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "RegisterMachineEx"); if (r < 0) return bus_log_create_error(r); @@ -209,45 +204,6 @@ static int create_or_register_machine_ex( if (r < 0) return bus_log_create_error(r); - if (!keep_unit) { - r = sd_bus_message_open_container(m, 'a', "(sv)"); - if (r < 0) - return bus_log_create_error(r); - - if (!isempty(slice)) { - r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); - if (r < 0) - return bus_log_create_error(r); - } - - r = append_controller_property(bus, m); - if (r < 0) - return r; - - r = append_machine_properties( - m, - mounts, - n_mounts, - kill_signal, - start_mode == START_BOOT && can_set_coredump_receive(bus) > 0); - if (r < 0) - return r; - - if (properties_message) { - r = sd_bus_message_copy(m, properties_message, true); - if (r < 0) - return bus_log_create_error(r); - } - - r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties); - if (r < 0) - return r; - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - } - return sd_bus_call(bus, m, 0, error, NULL); } @@ -258,117 +214,45 @@ int register_machine( const char *directory, sd_id128_t uuid, int local_ifindex, - const char *slice, - CustomMount *mounts, - unsigned n_mounts, - int kill_signal, - char **properties, - sd_bus_message *properties_message, - const char *service, - StartMode start_mode, - RegisterMachineFlags flags) { + const char *service) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); + assert(machine_name); + assert(service); - r = create_or_register_machine_ex( + r = register_machine_ex( bus, machine_name, pid, directory, uuid, local_ifindex, - slice, - mounts, - n_mounts, - kill_signal, - properties, - properties_message, service, - start_mode, - &error, - FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT)); + &error); if (r >= 0) return 0; if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r)); - sd_bus_error_free(&error); - if (FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT)) { - r = bus_call_method( - bus, - bus_machine_mgr, - "RegisterMachineWithNetwork", - &error, - NULL, - "sayssusai", - machine_name, - SD_BUS_MESSAGE_APPEND_ID128(uuid), - service, - "container", - pidref_is_set(pid) ? (uint32_t) pid->pid : 0, - strempty(directory), - local_ifindex > 0 ? 1 : 0, local_ifindex); - } else { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - - r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CreateMachineWithNetwork"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append( - m, - "sayssusai", - machine_name, - SD_BUS_MESSAGE_APPEND_ID128(uuid), - service, - "container", - pidref_is_set(pid) ? (uint32_t) pid->pid : 0, - strempty(directory), - local_ifindex > 0 ? 1 : 0, local_ifindex); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, 'a', "(sv)"); - if (r < 0) - return bus_log_create_error(r); - - if (!isempty(slice)) { - r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); - if (r < 0) - return bus_log_create_error(r); - } - - r = append_controller_property(bus, m); - if (r < 0) - return r; - - r = append_machine_properties( - m, - mounts, - n_mounts, - kill_signal, - start_mode == START_BOOT && can_set_coredump_receive(bus) > 0); - if (r < 0) - return r; - if (properties_message) { - r = sd_bus_message_copy(m, properties_message, true); - if (r < 0) - return bus_log_create_error(r); - } - - r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties); - if (r < 0) - return r; - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); + sd_bus_error_free(&error); - r = sd_bus_call(bus, m, 0, &error, NULL); - } + r = bus_call_method( + bus, + bus_machine_mgr, + "RegisterMachineWithNetwork", + &error, + NULL, + "sayssusai", + machine_name, + SD_BUS_MESSAGE_APPEND_ID128(uuid), + service, + "container", + pidref_is_set(pid) ? (uint32_t) pid->pid : 0, + strempty(directory), + local_ifindex > 0 ? 1 : 0, local_ifindex); if (r < 0) return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r)); diff --git a/src/nspawn/nspawn-register.h b/src/nspawn/nspawn-register.h index bbb0d9124e5..c81e4dac452 100644 --- a/src/nspawn/nspawn-register.h +++ b/src/nspawn/nspawn-register.h @@ -4,10 +4,6 @@ #include "forward.h" #include "nspawn-settings.h" -typedef enum RegisterMachineFlags { - REGISTER_MACHINE_KEEP_UNIT = 1 << 0, -} RegisterMachineFlags; - int register_machine( sd_bus *bus, const char *machine_name, @@ -15,14 +11,7 @@ int register_machine( const char *directory, sd_id128_t uuid, int local_ifindex, - const char *slice, - CustomMount *mounts, unsigned n_mounts, - int kill_signal, - char **properties, - sd_bus_message *properties_message, - const char *service, - StartMode start_mode, - RegisterMachineFlags flags); + const char *service); int unregister_machine(sd_bus *bus, const char *machine_name); typedef enum AllocateScopeFlags { diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index f1ed036b622..1fcd01d4bd9 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -5380,10 +5380,10 @@ static int run_container( (void) sd_bus_set_allow_interactive_authorization(system_bus, arg_ask_password); } - /* Scope allocation happens on the user bus if we are unpriv, otherwise system bus. */ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *user_bus = NULL; _cleanup_(sd_bus_unrefp) sd_bus *runtime_bus = NULL; - if (!arg_keep_unit) { + + if (arg_register || !arg_keep_unit) { if (arg_privileged) runtime_bus = sd_bus_ref(system_bus); else { @@ -5397,7 +5397,22 @@ static int run_container( runtime_bus = sd_bus_ref(user_bus); } + } + /* Scope allocation happens on the user bus if we are unpriv, otherwise system bus. */ + if (arg_keep_unit) { + /* If we are not supposed to allocate a unit, then let's move the process now, so that we can + * register things while being in the right cgroup location already. Otherwise, let's move + * the process later, once we have unit and hence cgroup. */ + r = create_subcgroup( + pid, + arg_keep_unit, + arg_uid_shift, + userns_fd, + arg_userns_mode); + if (r < 0) + return r; + } else { /* When a new scope is created for this container, then we'll be registered as its controller, in which * case PID 1 will send us a friendly RequestStop signal, when it is asked to terminate the * scope. Let's hook into that, and cleanly shut down the container, and print a friendly message. */ @@ -5416,22 +5431,8 @@ static int run_container( return log_error_errno(r, "Failed to request RequestStop match: %m"); } - if (arg_keep_unit) { - /* If we are not supposed to allocate a unit, then let's move the process now, so that we can - * register things while being in the right cgroup location already. Otherwise, let's move - * the process later, once we have unit and hence cgroup. */ - r = create_subcgroup( - pid, - arg_keep_unit, - arg_uid_shift, - userns_fd, - arg_userns_mode); - if (r < 0) - return r; - } - bool scope_allocated = false; - if (!arg_keep_unit && (!arg_register || !arg_privileged)) { + if (!arg_keep_unit) { AllocateScopeFlags flags = ALLOCATE_SCOPE_ALLOW_PIDFD; r = allocate_scope( runtime_bus, @@ -5450,10 +5451,8 @@ static int run_container( scope_allocated = true; } - bool registered = false; + bool registered_system = false, registered_runtime = false; if (arg_register) { - RegisterMachineFlags flags = 0; - SET_FLAG(flags, REGISTER_MACHINE_KEEP_UNIT, arg_keep_unit || !arg_privileged); r = register_machine( system_bus, arg_machine, @@ -5461,18 +5460,32 @@ static int run_container( arg_directory, arg_uuid, ifi, - arg_slice, - arg_custom_mounts, arg_n_custom_mounts, - arg_kill_signal, - arg_property, - arg_property_message, - arg_container_service_name, - arg_start_mode, - flags); - if (r < 0) - return r; + arg_container_service_name); + if (r < 0) { + if (arg_privileged) /* if privileged the request to register definitely failed */ + return r; + + log_notice_errno(r, "Failed to register machine in system context, will try in user context."); + } else + registered_system = true; - registered = true; + if (!arg_privileged) { + r = register_machine( + runtime_bus, + arg_machine, + pid, + arg_directory, + arg_uuid, + ifi, + arg_container_service_name); + if (r < 0) { + if (!registered_system) /* neither registration worked: fail */ + return r; + + log_notice_errno(r, "Failed to register machine in user context, but succeeded in system context, will proceed."); + } else + registered_runtime = true; + } } if (arg_keep_unit && (arg_slice || arg_property)) @@ -5684,8 +5697,10 @@ static int run_container( r = wait_for_container(pid, &container_status); /* Tell machined that we are gone. */ - if (registered) + if (registered_system) (void) unregister_machine(system_bus, arg_machine); + if (registered_runtime) + (void) unregister_machine(runtime_bus, arg_machine); if (r < 0) /* We failed to wait for the container, or the container exited abnormally. */ -- 2.47.3