mirror of
https://github.com/systemd/systemd.git
synced 2025-05-27 21:05:55 +03:00
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:
parent
1dfa58edd3
commit
3f37a82545
@ -139,6 +139,14 @@
|
||||
not be able to log via the syslog or journal protocols to the host logging infrastructure, unless the
|
||||
relevant sockets are mounted from the host, specifically:</para>
|
||||
|
||||
<para>The host's
|
||||
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
file will be made available for the service (read-only) as
|
||||
<filename>/run/host/os-release</filename>.
|
||||
It will be updated automatically on soft reboot (see:
|
||||
<citerefentry><refentrytitle>systemd-soft-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>),
|
||||
in case the service is configured to survive it.</para>
|
||||
|
||||
<example>
|
||||
<title>Mounting logging sockets into root environment</title>
|
||||
|
||||
@ -172,6 +180,14 @@
|
||||
<para>Units making use of <varname>RootImage=</varname> automatically gain an
|
||||
<varname>After=</varname> dependency on <filename>systemd-udevd.service</filename>.</para>
|
||||
|
||||
<para>The host's
|
||||
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
file will be made available for the service (read-only) as
|
||||
<filename>/run/host/os-release</filename>.
|
||||
It will be updated automatically on soft reboot (see:
|
||||
<citerefentry><refentrytitle>systemd-soft-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>),
|
||||
in case the service is configured to survive it.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -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
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "clock-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "confidential-virt.h"
|
||||
#include "copy.h"
|
||||
#include "cpu-set-util.h"
|
||||
#include "crash-handler.h"
|
||||
#include "dbus-manager.h"
|
||||
@ -1382,6 +1383,38 @@ static int os_release_status(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_os_release(RuntimeScope scope) {
|
||||
_cleanup_free_ char *os_release_dst = NULL;
|
||||
const char *os_release_src = "/etc/os-release";
|
||||
int r;
|
||||
|
||||
if (access("/etc/os-release", F_OK) < 0) {
|
||||
if (errno != ENOENT)
|
||||
log_debug_errno(errno, "Failed to check if /etc/os-release exists, ignoring: %m");
|
||||
|
||||
os_release_src = "/usr/lib/os-release";
|
||||
}
|
||||
|
||||
if (scope == RUNTIME_SCOPE_SYSTEM) {
|
||||
os_release_dst = strdup("/run/systemd/propagate/os-release");
|
||||
if (!os_release_dst)
|
||||
return log_oom_debug();
|
||||
} else {
|
||||
if (asprintf(&os_release_dst, "/run/user/" UID_FMT "/systemd/propagate/os-release", geteuid()) < 0)
|
||||
return log_oom_debug();
|
||||
}
|
||||
|
||||
r = mkdir_parents_label(os_release_dst, 0755);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return log_debug_errno(r, "Failed to create parent directory of %s, ignoring: %m", os_release_dst);
|
||||
|
||||
r = copy_file(os_release_src, os_release_dst, /* open_flags= */ 0, 0644, COPY_MAC_CREATE);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to create %s, ignoring: %m", os_release_dst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_container_id(void) {
|
||||
const char *c;
|
||||
int r = 0; /* avoid false maybe-uninitialized warning */
|
||||
@ -2253,6 +2286,12 @@ static int initialize_runtime(
|
||||
bump_file_max_and_nr_open();
|
||||
test_usr();
|
||||
write_container_id();
|
||||
|
||||
/* Copy os-release to the propagate directory, so that we update it for services running
|
||||
* under RootDirectory=/RootImage= when we do a soft reboot. */
|
||||
r = setup_os_release(RUNTIME_SCOPE_SYSTEM);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to copy os-release for propagation, ignoring: %m");
|
||||
}
|
||||
|
||||
r = watchdog_set_device(arg_watchdog_device);
|
||||
@ -2275,6 +2314,9 @@ static int initialize_runtime(
|
||||
|
||||
(void) mkdir_p_label(p, 0755);
|
||||
(void) make_inaccessible_nodes(p, UID_INVALID, GID_INVALID);
|
||||
r = setup_os_release(RUNTIME_SCOPE_USER);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to copy os-release for propagation, ignoring: %m");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1701,7 +1701,8 @@ static size_t namespace_calculate_mounts(
|
||||
const char *creds_path,
|
||||
const char* log_namespace,
|
||||
bool setup_propagate,
|
||||
const char* notify_socket) {
|
||||
const char* notify_socket,
|
||||
const char* host_os_release) {
|
||||
|
||||
size_t protect_home_cnt;
|
||||
size_t protect_system_cnt =
|
||||
@ -1746,6 +1747,7 @@ static size_t namespace_calculate_mounts(
|
||||
!!log_namespace +
|
||||
setup_propagate + /* /run/systemd/incoming */
|
||||
!!notify_socket +
|
||||
!!host_os_release +
|
||||
ns_info->private_network + /* /sys */
|
||||
ns_info->private_ipc; /* /dev/mqueue */
|
||||
}
|
||||
@ -2005,6 +2007,7 @@ int setup_namespace(
|
||||
const char *incoming_dir,
|
||||
const char *extension_dir,
|
||||
const char *notify_socket,
|
||||
const char *host_os_release,
|
||||
char **error_path) {
|
||||
|
||||
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||
@ -2130,7 +2133,8 @@ int setup_namespace(
|
||||
creds_path,
|
||||
log_namespace,
|
||||
setup_propagate,
|
||||
notify_socket);
|
||||
notify_socket,
|
||||
host_os_release);
|
||||
|
||||
if (n_mounts > 0) {
|
||||
m = mounts = new0(MountEntry, n_mounts);
|
||||
@ -2365,6 +2369,15 @@ int setup_namespace(
|
||||
.read_only = true,
|
||||
};
|
||||
|
||||
if (host_os_release)
|
||||
*(m++) = (MountEntry) {
|
||||
.path_const = "/run/host/os-release",
|
||||
.source_const = host_os_release,
|
||||
.mode = BIND_MOUNT,
|
||||
.read_only = true,
|
||||
.ignore = true, /* Live copy, don't hard-fail if it goes missing */
|
||||
};
|
||||
|
||||
assert(mounts + n_mounts == m);
|
||||
|
||||
/* Prepend the root directory where that's necessary */
|
||||
|
@ -133,6 +133,7 @@ int setup_namespace(
|
||||
const char *incoming_dir,
|
||||
const char *extension_dir,
|
||||
const char *notify_socket,
|
||||
const char *host_os_release,
|
||||
char **error_path);
|
||||
|
||||
#define RUN_SYSTEMD_EMPTY "/run/systemd/empty"
|
||||
|
@ -1052,20 +1052,12 @@ static int install_chroot_dropin(
|
||||
return log_debug_errno(r, "Failed to generate marker string for portable drop-in: %m");
|
||||
|
||||
if (endswith(m->name, ".service")) {
|
||||
const char *os_release_source, *root_type;
|
||||
const char *root_type;
|
||||
_cleanup_free_ char *base_name = NULL;
|
||||
Image *ext;
|
||||
|
||||
root_type = root_setting_from_image(type);
|
||||
|
||||
if (access("/etc/os-release", F_OK) < 0) {
|
||||
if (errno != ENOENT)
|
||||
return log_debug_errno(errno, "Failed to check if /etc/os-release exists: %m");
|
||||
|
||||
os_release_source = "/usr/lib/os-release";
|
||||
} else
|
||||
os_release_source = "/etc/os-release";
|
||||
|
||||
r = path_extract_filename(m->image_path ?: image_path, &base_name);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to extract basename from '%s': %m", m->image_path ?: image_path);
|
||||
@ -1075,7 +1067,6 @@ static int install_chroot_dropin(
|
||||
"[Service]\n",
|
||||
root_type, image_path, "\n"
|
||||
"Environment=PORTABLE=", base_name, "\n"
|
||||
"BindReadOnlyPaths=", os_release_source, ":/run/host/os-release\n"
|
||||
"LogExtraFields=PORTABLE=", base_name, "\n"))
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -205,6 +205,7 @@ TEST(protect_kernel_logs) {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
assert_se(r == 0);
|
||||
|
||||
|
@ -107,6 +107,7 @@ int main(int argc, char *argv[]) {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set up namespace: %m");
|
||||
|
@ -583,4 +583,6 @@ grep -q -F "MARKER_CONFEXT_123" /etc/testfile
|
||||
systemd-confext unmerge
|
||||
rm -rf /run/confexts/ testjob/
|
||||
|
||||
systemd-run -P -p RootImage="${image}.raw" cat /run/host/os-release | cmp "${os_release}"
|
||||
|
||||
touch /testok
|
||||
|
@ -54,6 +54,8 @@ elif [ -f /run/testsuite82.touch2 ]; then
|
||||
# Test that we really are in the new overlayfs root fs
|
||||
read -r x </lower
|
||||
test "$x" = "miep"
|
||||
cmp /etc/os-release /run/systemd/propagate/os-release
|
||||
grep -q MARKER=1 /etc/os-release
|
||||
|
||||
# Switch back to the original root, away from the overlayfs
|
||||
mount --bind /original-root /run/nextroot
|
||||
@ -92,7 +94,16 @@ elif [ -f /run/testsuite82.touch ]; then
|
||||
mkdir -p /run/nextroot /tmp/nextroot-lower /original-root
|
||||
mount -t tmpfs tmpfs /tmp/nextroot-lower
|
||||
echo miep >/tmp/nextroot-lower/lower
|
||||
mount -t overlay nextroot /run/nextroot -o lowerdir=/:/tmp/nextroot-lower,ro
|
||||
|
||||
# Copy os-release away, so that we can manipulate it and check that it is updated in the propagate
|
||||
# directory across soft reboots.
|
||||
mkdir -p /tmp/nextroot-lower/usr/lib
|
||||
cp /etc/os-release /tmp/nextroot-lower/usr/lib/os-release
|
||||
echo MARKER=1 >>/tmp/nextroot-lower/usr/lib/os-release
|
||||
cmp /etc/os-release /run/systemd/propagate/os-release
|
||||
(! grep -q MARKER=1 /etc/os-release)
|
||||
|
||||
mount -t overlay nextroot /run/nextroot -o lowerdir=/tmp/nextroot-lower:/,ro
|
||||
|
||||
# Bind our current root into the target so that we later can return to it
|
||||
mount --bind / /run/nextroot/original-root
|
||||
|
Loading…
x
Reference in New Issue
Block a user