]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
switch-root: when switching root via MS_MOVE unmount all remaining mounts first 27670/head
authorLennart Poettering <lennart@poettering.net>
Mon, 15 May 2023 19:25:12 +0000 (21:25 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 17 May 2023 08:30:47 +0000 (10:30 +0200)
Let's try to unmount anything left, since if we don't they will remain
as "shadow" mounts, hidden underneath our new root.

This is only necessary when we transition into a new root via MS_MOVE.
If we do so via pivot_root() this is not necessary as the kernel will
get rid of the mounts anyway for us.

src/shared/switch-root.c

index 1ee06c8ee4db8901dd10d8db24936934f17713bc..2431facba006422f30ff57996f17a1772f794bd4 100644 (file)
@@ -114,6 +114,14 @@ int switch_root(const char *new_root,
         if (r < 0) {
                 log_debug_errno(r, "Pivoting root file system failed, moving mounts instead: %m");
 
+                /* If we have to use MS_MOVE let's first try to get rid of *all* mounts we can, with the
+                 * exception of the path we want to switch to, plus everything leading to it and within
+                 * it. This is necessary because unlike pivot_root() just moving the mount to the root via
+                 * MS_MOVE won't magically unmount anything below it. Once the chroot() succeeds the mounts
+                 * below would still be around but invisible to us, because not accessible via
+                 * /proc/self/mountinfo. Hence, let's clean everything up first, as long as we still can. */
+                (void) umount_recursive_full(NULL, MNT_DETACH, STRV_MAKE(new_root));
+
                 if (mount(".", "/", NULL, MS_MOVE, NULL) < 0)
                         return log_error_errno(errno, "Failed to move %s to /: %m", new_root);