core: copy the host's os-release for /run/host/os-release

Currently for portable services we automatically add a bind mount
os-release -> /run/host/os-release. This becomes problematic for the
soft-reboot case, as it's likely that portable services will be configured
to survive it, and thus would forever keep a reference to the old host's
os-release, which would be a problem because it becomes outdated, and also
it stops the old rootfs from being garbage collected.

Create a copy when the manager starts under /run/systemd/propagate instead,
and bind mount that for all services using RootDirectory=/RootImage=, so
that on soft-reboot the content gets updated (without creating a new file,
so the existing bind mounts will see the new content too).

This expands the /run/host/os-release protocol to more services, but I
think that's a nice thing to have too.

Closes https://github.com/systemd/systemd/issues/28023
This commit is contained in:
Luca Boccassi
2023-07-18 17:26:02 +01:00
parent 1dfa58edd3
commit 3f37a82545
10 changed files with 106 additions and 14 deletions
+15 -1
View File
@@ -3967,7 +3967,7 @@ static int apply_mount_namespace(
_cleanup_strv_free_ char **empty_directories = NULL, **symlinks = NULL,
**read_write_paths_cleanup = NULL;
_cleanup_free_ char *creds_path = NULL, *incoming_dir = NULL, *propagate_dir = NULL,
*extension_dir = NULL;
*extension_dir = NULL, *host_os_release = NULL;
const char *root_dir = NULL, *root_image = NULL, *tmp_dir = NULL, *var_tmp_dir = NULL;
char **read_write_paths;
NamespaceInfo ns_info;
@@ -4087,11 +4087,24 @@ static int apply_mount_namespace(
extension_dir = strdup("/run/systemd/unit-extensions");
if (!extension_dir)
return -ENOMEM;
/* If running under a different root filesystem, propagate the host's os-release. We make a
* copy rather than just bind mounting it, so that it can be updated on soft-reboot. */
if (root_dir || root_image) {
host_os_release = strdup("/run/systemd/propagate/os-release");
if (!host_os_release)
return -ENOMEM;
}
} else {
assert(params->runtime_scope == RUNTIME_SCOPE_USER);
if (asprintf(&extension_dir, "/run/user/" UID_FMT "/systemd/unit-extensions", geteuid()) < 0)
return -ENOMEM;
if (root_dir || root_image) {
if (asprintf(&host_os_release, "/run/user/" UID_FMT "/systemd/propagate/os-release", geteuid()) < 0)
return -ENOMEM;
}
}
if (root_image) {
@@ -4139,6 +4152,7 @@ static int apply_mount_namespace(
incoming_dir,
extension_dir,
root_dir || root_image ? params->notify_socket : NULL,
host_os_release,
error_path);
/* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports