nspawn: register containers in both user and system machined if applicable (#39145)

This commit is contained in:
Lennart Poettering
2025-10-14 11:58:29 +02:00
committed by GitHub
4 changed files with 121 additions and 209 deletions

View File

@@ -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);
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));

View File

@@ -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 {

View File

@@ -18,6 +18,7 @@
#include "sd-event.h"
#include "sd-id128.h"
#include "sd-netlink.h"
#include "sd-path.h"
#include "alloc-util.h"
#include "barrier.h"
@@ -4936,30 +4937,49 @@ static int load_settings(void) {
if (FLAGS_SET(arg_settings_mask, _SETTINGS_MASK_ALL))
return 0;
/* We first look in the admin's directories in /etc and /run */
if (arg_privileged)
FOREACH_STRING(i, "/etc/systemd/nspawn", "/run/systemd/nspawn") {
_cleanup_free_ char *j = NULL;
/* We first look in the admin's directories in /etc/ and /run/ */
static const uint64_t lookup_dir_system[] = {
SD_PATH_SYSTEM_CONFIGURATION,
SD_PATH_SYSTEM_RUNTIME,
_SD_PATH_INVALID,
};
static const uint64_t lookup_dir_user[] = {
SD_PATH_USER_CONFIGURATION,
SD_PATH_USER_RUNTIME,
_SD_PATH_INVALID,
};
j = path_join(i, arg_settings_filename);
if (!j)
return log_oom();
f = fopen(j, "re");
if (f) {
p = TAKE_PTR(j);
/* By default, we trust configuration from /etc and /run */
if (arg_settings_trusted < 0)
arg_settings_trusted = true;
break;
}
if (errno != ENOENT)
return log_error_errno(errno, "Failed to open %s: %m", j);
const uint64_t *q = arg_privileged ? lookup_dir_system : lookup_dir_user;
for (; *q != _SD_PATH_INVALID; q++) {
_cleanup_free_ char *cd = NULL;
r = sd_path_lookup(*q, "systemd/nspawn", &cd);
if (r < 0) {
log_warning_errno(r, "Failed to determine settings directory, ignoring: %m");
continue;
}
_cleanup_free_ char *j = NULL;
j = path_join(cd, arg_settings_filename);
if (!j)
return log_oom();
f = fopen(j, "re");
if (f) {
p = TAKE_PTR(j);
log_debug("Found settings file: %s", p);
/* By default, we trust configuration from /etc and /run */
if (arg_settings_trusted < 0)
arg_settings_trusted = true;
break;
}
if (errno != ENOENT)
return log_error_errno(errno, "Failed to open %s: %m", j);
}
if (!f) {
/* After that, let's look for a file next to the
* actual image we shall boot. */
@@ -4979,6 +4999,9 @@ static int load_settings(void) {
if (!f && errno != ENOENT)
return log_error_errno(errno, "Failed to open %s: %m", p);
if (f)
log_debug("Found settings file: %s", p);
/* By default, we do not trust configuration from /var/lib/machines */
if (arg_settings_trusted < 0)
arg_settings_trusted = false;
@@ -5357,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 {
@@ -5374,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. */
@@ -5393,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,
@@ -5427,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,
@@ -5438,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;
registered = true;
log_notice_errno(r, "Failed to register machine in system context, will try in user context.");
} else
registered_system = 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))
@@ -5661,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. */

View File

@@ -21,7 +21,7 @@
_SD_BEGIN_DECLARATIONS;
enum {
__extension__ enum {
/* Temporary files */
SD_PATH_TEMPORARY,
SD_PATH_TEMPORARY_LARGE,
@@ -129,7 +129,8 @@ enum {
SD_PATH_USER_CREDENTIAL_STORE_ENCRYPTED,
SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED,
_SD_PATH_MAX
_SD_PATH_MAX,
_SD_PATH_INVALID = UINT64_MAX
};
int sd_path_lookup(uint64_t type, const char *suffix, char **ret);