Skip to content

Commit 2bfe726

Browse files
authored
Merge pull request #28497 from bluca/run
switch-root: use MS_REC for /run, unless we are soft-rebooting
2 parents 16bfb12 + 8256994 commit 2bfe726

File tree

5 files changed

+53
-10
lines changed

5 files changed

+53
-10
lines changed

src/core/main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1884,7 +1884,8 @@ static int do_reexecute(
18841884
if (switch_root_dir) {
18851885
r = switch_root(/* new_root= */ switch_root_dir,
18861886
/* old_root_after= */ NULL,
1887-
/* flags= */ objective == MANAGER_SWITCH_ROOT ? SWITCH_ROOT_DESTROY_OLD_ROOT : 0);
1887+
/* flags= */ (objective == MANAGER_SWITCH_ROOT ? SWITCH_ROOT_DESTROY_OLD_ROOT : 0) |
1888+
(objective == MANAGER_SOFT_REBOOT ? SWITCH_ROOT_SKIP_RECURSIVE_RUN : 0));
18881889
if (r < 0)
18891890
log_error_errno(r, "Failed to switch root, trying to continue: %m");
18901891
}

src/shared/switch-root.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,23 @@ int switch_root(const char *new_root,
3030
const char *old_root_after, /* path below the new root, where to place the old root after the transition; may be NULL to unmount it */
3131
SwitchRootFlags flags) {
3232

33+
/* Stuff mounted below /run we don't save on soft reboot, as it might have lost its relevance, i.e.
34+
* credentials, removable media and such, we rather want that the new boot mounts this fresh.
35+
* But on the switch from initrd we do use MS_REC, as it is expected that mounts set up in /run
36+
* are maintained. */
37+
unsigned long run_mount_flags = MS_BIND|(!FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_RUN) ? MS_REC : 0);
3338
struct {
3439
const char *path;
3540
unsigned long mount_flags;
41+
bool skip_if_run_is_rec; /* For child mounts of /run, if it's moved recursively no need to handle */
3642
} transfer_table[] = {
37-
{ "/dev", MS_BIND|MS_REC }, /* Recursive, because we want to save the original /dev/shm + /dev/pts and similar */
38-
{ "/sys", MS_BIND|MS_REC }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
39-
{ "/proc", MS_BIND|MS_REC }, /* Similar */
40-
{ "/run", MS_BIND }, /* Stuff mounted below this we don't save, as it might have lost its relevance, i.e. credentials, removable media and such, we rather want that the new boot mounts this fresh */
41-
{ SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND }, /* Credentials passed into the system should survive */
42-
{ ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND }, /* Similar */
43-
{ "/run/host", MS_BIND|MS_REC }, /* Host supplied hierarchy should also survive */
43+
{ "/dev", MS_BIND|MS_REC, false }, /* Recursive, because we want to save the original /dev/shm + /dev/pts and similar */
44+
{ "/sys", MS_BIND|MS_REC, false }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
45+
{ "/proc", MS_BIND|MS_REC, false }, /* Similar */
46+
{ "/run", run_mount_flags, false }, /* Recursive except on soft reboot, see above */
47+
{ SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND, true }, /* Credentials passed into the system should survive */
48+
{ ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND, true }, /* Similar */
49+
{ "/run/host", MS_BIND|MS_REC, true }, /* Host supplied hierarchy should also survive */
4450
};
4551

4652
_cleanup_close_ int old_root_fd = -EBADF, new_root_fd = -EBADF;
@@ -112,6 +118,9 @@ int switch_root(const char *new_root,
112118
FOREACH_ARRAY(transfer, transfer_table, ELEMENTSOF(transfer_table)) {
113119
_cleanup_free_ char *chased = NULL;
114120

121+
if (transfer->skip_if_run_is_rec && !FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_RUN))
122+
continue;
123+
115124
if (access(transfer->path, F_OK) < 0) {
116125
log_debug_errno(errno, "Path '%s' to move to target root directory, not found, ignoring: %m", transfer->path);
117126
continue;

src/shared/switch-root.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
#include <stdbool.h>
55

66
typedef enum SwitchRootFlags {
7-
SWITCH_ROOT_DESTROY_OLD_ROOT = 1 << 0, /* rm -rf old root when switching – under the condition that it is backed by non-persistent tmpfs/ramfs/… */
8-
SWITCH_ROOT_DONT_SYNC = 1 << 1, /* don't call sync() immediately before switching root */
7+
SWITCH_ROOT_DESTROY_OLD_ROOT = 1 << 0, /* rm -rf old root when switching – under the condition that it is backed by non-persistent tmpfs/ramfs/… */
8+
SWITCH_ROOT_DONT_SYNC = 1 << 1, /* don't call sync() immediately before switching root */
9+
SWITCH_ROOT_SKIP_RECURSIVE_RUN = 1 << 2, /* move /run without MS_REC */
910
} SwitchRootFlags;
1011

1112
int switch_root(const char *new_root, const char *old_root_after, SwitchRootFlags flags);

test/TEST-01-BASIC/test.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,31 @@ test_append_files() {
2323
cp -v "$TEST_UNITS_DIR"/{testsuite-01,end}.service "$TEST_UNITS_DIR/testsuite.target" "$dst"
2424
}
2525

26+
# Setup a one shot service in initrd that creates a dummy bind mount under /run
27+
# to check if the mount persists though the initrd transition. The "check" part
28+
# is in the respective testsuite-01.sh script.
29+
#
30+
# See: https://github.com/systemd/systemd/issues/28452
31+
run_qemu_hook() {
32+
local extra="$WORKDIR/initrd.extra"
33+
34+
mkdir -m 755 "$extra"
35+
mkdir -m 755 "$extra/etc" "$extra/etc/systemd" "$extra/etc/systemd/system" "$extra/etc/systemd/system/initrd.target.wants"
36+
37+
cat >"$extra/etc/systemd/system/initrd-run-mount.service" <<EOF
38+
[Unit]
39+
Description=Create a mount in /run that should survive the transition from initrd
40+
41+
[Service]
42+
Type=oneshot
43+
RemainAfterExit=yes
44+
ExecStart=sh -xec "mkdir /run/initrd-mount-source /run/initrd-mount-target; mount -v --bind /run/initrd-mount-source /run/initrd-mount-target"
45+
EOF
46+
ln -svrf "$extra/etc/systemd/system/initrd-run-mount.service" "$extra/etc/systemd/system/initrd.target.wants/initrd-run-mount.service"
47+
48+
(cd "$extra" && find . | cpio -o -H newc -R root:root > "$extra.cpio")
49+
50+
INITRD_EXTRA="$extra.cpio"
51+
}
52+
2653
do_test "$@"

test/units/testsuite-01.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ if systemd-detect-virt -q --container; then
1919
test ! -e /run/systemd/container
2020
cp -afv /tmp/container /run/systemd/container
2121
else
22+
# We should've created a mount under /run in initrd (see the other half of the test)
23+
# that should've survived the transition from initrd to the real system
24+
test -d /run/initrd-mount-target
25+
mountpoint /run/initrd-mount-target
26+
2227
# We bring the loopback netdev up only during a full setup, so it should
2328
# not get brought back up during reexec if we disable it beforehand
2429
[[ "$(ip -o link show lo)" =~ LOOPBACK,UP ]]

0 commit comments

Comments
 (0)