]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
switch-root: use MS_REC for /run, unless we are soft-rebooting
authorLuca Boccassi <bluca@debian.org>
Sat, 22 Jul 2023 21:45:16 +0000 (22:45 +0100)
committerLuca Boccassi <bluca@debian.org>
Mon, 24 Jul 2023 09:39:14 +0000 (10:39 +0100)
There are applications that rely on mounts under /run surviving the
switch from initrd to rootfs, so use MS_REC unless we are soft
rebooting.

Follow-up for 7c764d45997721705e43ac66fbb5a56747d00d40

Fixes https://github.com/systemd/systemd/issues/28452

src/core/main.c
src/shared/switch-root.c
src/shared/switch-root.h

index 7094be8dba0648ecb3685ac3ebc6c5e8213011f7..913dc0cf7e00ff7bf0bb840dfa4c2a1c11777d29 100644 (file)
@@ -1884,7 +1884,8 @@ static int do_reexecute(
         if (switch_root_dir) {
                 r = switch_root(/* new_root= */ switch_root_dir,
                                 /* old_root_after= */ NULL,
-                                /* flags= */ objective == MANAGER_SWITCH_ROOT ? SWITCH_ROOT_DESTROY_OLD_ROOT : 0);
+                                /* flags= */ (objective == MANAGER_SWITCH_ROOT ? SWITCH_ROOT_DESTROY_OLD_ROOT : 0) |
+                                             (objective == MANAGER_SOFT_REBOOT ? SWITCH_ROOT_SKIP_RECURSIVE_RUN : 0));
                 if (r < 0)
                         log_error_errno(r, "Failed to switch root, trying to continue: %m");
         }
index 070d5bd908b3c24b7cc70b06176afef2e338558a..37395e02ad4cf8367dc25038bb562920d2c67817 100644 (file)
@@ -30,17 +30,23 @@ int switch_root(const char *new_root,
                 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 */
                 SwitchRootFlags flags) {
 
+        /* Stuff mounted below /run we don't save on soft reboot, as it might have lost its relevance, i.e.
+         * credentials, removable media and such, we rather want that the new boot mounts this fresh.
+         * But on the switch from initrd we do use MS_REC, as it is expected that mounts set up in /run
+         * are maintained. */
+        unsigned long run_mount_flags = MS_BIND|(!FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_RUN) ? MS_REC : 0);
         struct {
                 const char *path;
                 unsigned long mount_flags;
+                bool skip_if_run_is_rec; /* For child mounts of /run, if it's moved recursively no need to handle */
         } transfer_table[] = {
-                { "/dev",                                 MS_BIND|MS_REC }, /* Recursive, because we want to save the original /dev/shm + /dev/pts and similar */
-                { "/sys",                                 MS_BIND|MS_REC }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
-                { "/proc",                                MS_BIND|MS_REC }, /* Similar */
-                { "/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 */
-                { SYSTEM_CREDENTIALS_DIRECTORY,           MS_BIND        }, /* Credentials passed into the system should survive */
-                { ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND        }, /* Similar */
-                { "/run/host",                            MS_BIND|MS_REC }, /* Host supplied hierarchy should also survive */
+                { "/dev",                                 MS_BIND|MS_REC,  false }, /* Recursive, because we want to save the original /dev/shm + /dev/pts and similar */
+                { "/sys",                                 MS_BIND|MS_REC,  false }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
+                { "/proc",                                MS_BIND|MS_REC,  false }, /* Similar */
+                { "/run",                                 run_mount_flags, false }, /* Recursive except on soft reboot, see above */
+                { SYSTEM_CREDENTIALS_DIRECTORY,           MS_BIND,         true },  /* Credentials passed into the system should survive */
+                { ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND,         true },  /* Similar */
+                { "/run/host",                            MS_BIND|MS_REC,  true },  /* Host supplied hierarchy should also survive */
         };
 
         _cleanup_close_ int old_root_fd = -EBADF, new_root_fd = -EBADF;
@@ -112,6 +118,9 @@ int switch_root(const char *new_root,
         FOREACH_ARRAY(transfer, transfer_table, ELEMENTSOF(transfer_table)) {
                 _cleanup_free_ char *chased = NULL;
 
+                if (transfer->skip_if_run_is_rec && !FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_RUN))
+                        continue;
+
                 if (access(transfer->path, F_OK) < 0) {
                         log_debug_errno(errno, "Path '%s' to move to target root directory, not found, ignoring: %m", transfer->path);
                         continue;
index 79e47c67f471ba3f96c192d66caf39df9ffc60eb..78d62f28e04312a8ff93ce229e461802bf154e2a 100644 (file)
@@ -4,8 +4,9 @@
 #include <stdbool.h>
 
 typedef enum SwitchRootFlags {
-        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/… */
-        SWITCH_ROOT_DONT_SYNC        = 1 << 1, /* don't call sync() immediately before switching root */
+        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/… */
+        SWITCH_ROOT_DONT_SYNC          = 1 << 1, /* don't call sync() immediately before switching root */
+        SWITCH_ROOT_SKIP_RECURSIVE_RUN = 1 << 2, /* move /run without MS_REC */
 } SwitchRootFlags;
 
 int switch_root(const char *new_root, const char *old_root_after, SwitchRootFlags flags);