Skip to content

Instantly share code, notes, and snippets.

@dbnicholson
Created October 4, 2017 10:54
Show Gist options
  • Save dbnicholson/da8aa72ea3bd7ee8731c9da2792fd5a3 to your computer and use it in GitHub Desktop.
Save dbnicholson/da8aa72ea3bd7ee8731c9da2792fd5a3 to your computer and use it in GitHub Desktop.
diff --git a/bind-mount.c b/bind-mount.c
index 7d3543f..d069c96 100644
--- a/bind-mount.c
+++ b/bind-mount.c
@@ -438,3 +438,27 @@ bind_mount (int proc_fd,
return 0;
}
+
+bool
+mount_exists (int proc_fd,
+ const char *path)
+{
+ cleanup_free char *resolved_path = NULL;
+ cleanup_mount_tab MountTab mount_tab = NULL;
+
+ /* The mount operation will resolve any symlinks in the destination
+ path, so to find it in the mount table we need to do that too. */
+ resolved_path = realpath (path, NULL);
+ if (resolved_path == NULL)
+ return FALSE;
+
+ mount_tab = parse_mountinfo (proc_fd, resolved_path);
+ if (mount_tab[0].mountpoint == NULL)
+ {
+ /* No mountpoint at dest */
+ errno = ENOENT;
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/bind-mount.h b/bind-mount.h
index c763763..b0f468a 100644
--- a/bind-mount.h
+++ b/bind-mount.h
@@ -28,3 +28,6 @@ int bind_mount (int proc_fd,
const char *src,
const char *dest,
bind_option_t options);
+
+bool mount_exists (int proc_fd,
+ const char *path);
diff --git a/bubblewrap.c b/bubblewrap.c
index 6e04459..8371fb9 100644
--- a/bubblewrap.c
+++ b/bubblewrap.c
@@ -1853,12 +1853,32 @@ main (int argc,
/* Need to do this before the chroot, but after we're the real uid */
resolve_symlinks_in_ops ();
- /* Mark everything as slave, so that we still
- * receive mounts from the real root, but don't
- * propagate mounts to the real root. */
+ if (!mount_exists (proc_fd, "/"))
+ {
+ printf("No / mount\n");
+ if (errno != ENOENT)
+ die_with_error ("Failed to get mount entry for /");
+
+ /* No / mount, likely in a chroot. Bind mount / to itself so that
+ * the subsequent slave mark succeeds. */
+ if (mount ("/", "/", NULL, MS_BIND| MS_REC, NULL) < 0)
+ die_with_error ("Failed to mount /");
+ }
+
+ /* Mark everything as slave, so that we still receive mounts from the
+ * real root, but don't propagate mounts to the real root. This also
+ * satisfies the pivot_root requirement that the old root mount is not
+ * shared. */
if (mount (NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
die_with_error ("Failed to make / slave");
+ /* pivot_root requires that both the old root and its parent are not
+ * shared mounts. To ensure control of the parent mount, bind mount /
+ * to itself. Since / was marked as slave above, both mounts will be
+ * non-shared. */
+ if (mount ("/", "/", NULL, MS_BIND| MS_REC, NULL) < 0)
+ die_with_error ("Failed to bind mount / to itself");
+
/* Create a tmpfs which we will use as / in the namespace */
if (mount ("", base_path, "tmpfs", MS_NODEV | MS_NOSUID, NULL) != 0)
die_with_error ("Failed to mount tmpfs");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment