Adding a warning when switchroot is used
authorEli Zrihen <ezrihen@gmail.com>
Tue, 20 Jul 2021 07:20:23 +0000 (10:20 +0300)
committerEli Zrihen <ezrihen@gmail.com>
Tue, 20 Jul 2021 07:20:23 +0000 (10:20 +0300)
cmdline.cc
mnt.cc

index 759bfdcd5f1df78faa8f53222f8a9f0bc67e0b3b..26626bae53820055dc4a32be6399f1c800f37e13 100644 (file)
@@ -76,7 +76,7 @@ struct custom_option custom_opts[] = {
     { { "exec_file", required_argument, NULL, 'x' }, "File to exec (default: argv[0])" },
     { { "execute_fd", no_argument, NULL, 0x0607 }, "Use execveat() to execute a file-descriptor instead of executing the binary path. In such case argv[0]/exec_file denotes a file path before mount namespacing" },
     { { "chroot", required_argument, NULL, 'c' }, "Directory containing / of the jail (default: none)" },
-    { { "use_switchroot", no_argument, NULL, 0x600 }, "When creating a mount namespace, use switch_root rather then the default pivot_root (usefull when using rootfs, on which the kernel disallows pivot_root)" },
+    { { "use_switchroot", no_argument, NULL, 0x600 }, "When creating a mount namespace, use switch_root rather then pivot_root. Usefull when pivot_root is disallowed (e.g. initramfs). Note: escapable is some configuration" },
     { { "rw", no_argument, NULL, 0x601 }, "Mount chroot dir (/) R/W (default: R/O)" },
     { { "user", required_argument, NULL, 'u' }, "Username/uid of processes inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid:count convention here. Can be specified multiple times" },
     { { "group", required_argument, NULL, 'g' }, "Groupname/gid of processes inside the jail (default: your current gid). You can also use inside_ns_gid:global_ns_gid:count convention here. Can be specified multiple times" },
diff --git a/mnt.cc b/mnt.cc
index 670567405bbdb42ef9e4ceea2e6733ce914b2ec0..413c9c66485e8f9b12b2725119ba9db03f9babb0 100644 (file)
--- a/mnt.cc
+++ b/mnt.cc
@@ -426,22 +426,28 @@ static bool initCloneNs(nsjconf_t* nsjconf) {
         * and there is no other file system that is mounted on top of it.In such systems,
         * there is no option to pivot_root!
         * For more information, see kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt.
-        * The alternative is to override '/' mount point with the new root within the mount namespace.
+        * switch_root alternative:
+        * Innstead of un-mounting the old rootfs, it is over mounted by moving the new root to it.
         */
+       
+        /* NOTE: Using mount move and chroot allows escaping back into the old root when proper
+        * capabilities are kept in the user namespace. It can be acheived by unmounting the new root
+        * and using setns to re-enter the mount namespace.
+        */
+               LOG_W(
+                           "Using switch_root is escapable when user posseses relevant capabilities, "
+                           "Use it with care!"
+        );
+               
         if (chdir(destdir->c_str()) == -1) {
             PLOG_E("chdir('%s')", destdir->c_str());
             return false;
         }
 
-        /* Override '/' mount point with the target chroot dir */
-        if (mount(".", "/", NULL, MS_REC | MS_BIND, NULL) == -1) {
-            PLOG_E("mount('.', '/', NULL, MS_REC | MS_BIND, NULL)");
-            return false;
-        }
-               
-        /* Remount '/' as private so that there will be no mount propagation */
-        if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == -1) {
-            PLOG_E("mount(NULL, '/', NULL, MS_REC | MS_BIND, NULL)");
+        /* mount moving the new root on top of '/'. This operation is atomic and doesn't involve
+        un-mounting '/' at any stage */
+        if (mount(".", "/", NULL, MS_MOVE, NULL) == -1) {
+            PLOG_E("mount('/', %s, NULL, MS_MOVE, NULL)", destdir->c_str());
             return false;
         }