[lxc-devel] [lxcfs/master] lxcfs on ramfs

brauner on Github lxc-bot at linuxcontainers.org
Sun Sep 4 16:39:20 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 934 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160904/4dfbdf7c/attachment.bin>
-------------- next part --------------
From 9601d540c0f5a0ebfc71491356b6ca6226f161ef Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Sun, 4 Sep 2016 17:33:09 +0200
Subject: [PATCH 1/3] bindings: add function to check fs type

We use statfs directly because statvfs proved unreliable in my testing. It's
f_fsid field does not seem to work correctly with linux/magic.h macros.

Signed-off-by: Christian Brauner <christian.brauner at mailbox.org>
---
 bindings.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/bindings.c b/bindings.c
index ac88f48..be2b163 100644
--- a/bindings.c
+++ b/bindings.c
@@ -22,6 +22,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <wait.h>
+#include <linux/magic.h>
 #include <linux/sched.h>
 #include <sys/epoll.h>
 #include <sys/mman.h>
@@ -29,6 +30,7 @@
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/syscall.h>
+#include <sys/vfs.h>
 
 #include "bindings.h"
 #include "config.h" // for VERSION
@@ -4149,6 +4151,11 @@ static bool umount_if_mounted(void)
 	return true;
 }
 
+bool has_fs_type(const struct statfs *fs, __fsword_t magic_val)
+{
+	return (fs->f_type == (__fsword_t)magic_val);
+}
+
 static int pivot_enter(void)
 {
 	int ret = -1, oldroot = -1, newroot = -1;

From a61c06a971a7e8861dd9c0714f7039eabce01a18 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Sun, 4 Sep 2016 17:42:22 +0200
Subject: [PATCH 2/3] bindings: agnostic naming

- non-functional changes

Signed-off-by: Christian Brauner <christian.brauner at mailbox.org>
---
 bindings.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/bindings.c b/bindings.c
index be2b163..9ff6c1f 100644
--- a/bindings.c
+++ b/bindings.c
@@ -4156,7 +4156,7 @@ bool has_fs_type(const struct statfs *fs, __fsword_t magic_val)
 	return (fs->f_type == (__fsword_t)magic_val);
 }
 
-static int pivot_enter(void)
+static int permute_and_enter(void)
 {
 	int ret = -1, oldroot = -1, newroot = -1;
 
@@ -4214,7 +4214,7 @@ static int pivot_enter(void)
 }
 
 /* Prepare our new clean root. */
-static int pivot_prepare(void)
+static int permute_prepare(void)
 {
 	if (mkdir(ROOTDIR, 0700) < 0 && errno != EEXIST) {
 		lxcfs_error("%s\n", "Failed to create directory for new root.");
@@ -4239,14 +4239,15 @@ static int pivot_prepare(void)
 	return 0;
 }
 
-static bool pivot_new_root(void)
+/* Calls chroot() on ramfs, pivot_root() in all other cases. */
+static bool permute_root(void)
 {
 	/* Prepare new root. */
-	if (pivot_prepare() < 0)
+	if (permute_prepare() < 0)
 		return false;
 
 	/* Pivot into new root. */
-	if (pivot_enter() < 0)
+	if (permute_and_enter() < 0)
 		return false;
 
 	return true;
@@ -4330,7 +4331,7 @@ static bool cgfs_setup_controllers(void)
 		return false;
 	}
 
-	if (!pivot_new_root())
+	if (!permute_root())
 		return false;
 
 	return true;

From 80b1bee81320195c7dd1893953519d76e4c1d054 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at mailbox.org>
Date: Sun, 4 Sep 2016 18:07:01 +0200
Subject: [PATCH 3/3] bindings: use chroot() on ramfs

- Detect whether we are on a ramfs. We first try via statfs and check for
  RAMFS_MAGIC. This may report TMPFS_MAGIC although it should better report
  RAMFS_MAGIC. In this case, parse /proc/self/mountinfo and check for
        - rootfs rootfs
  like we do in LXC.
- When we are on ramfs use chroot(), otherwise use pivot_root().

Signed-off-by: Christian Brauner <christian.brauner at mailbox.org>
---
 bindings.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 117 insertions(+), 33 deletions(-)

diff --git a/bindings.c b/bindings.c
index 9ff6c1f..c27a9d3 100644
--- a/bindings.c
+++ b/bindings.c
@@ -4151,14 +4151,118 @@ static bool umount_if_mounted(void)
 	return true;
 }
 
-bool has_fs_type(const struct statfs *fs, __fsword_t magic_val)
+/*
+ * looking at fs/proc_namespace.c, it appears we can
+ * actually expect the rootfs entry to very specifically contain
+ * " - rootfs rootfs "
+ * IIUC, so long as we've chrooted so that rootfs is not our root,
+ * the rootfs entry should always be skipped in mountinfo contents.
+ */
+static bool is_on_ramfs(void)
+{
+	FILE *f;
+	char *p, *p2;
+	char *line = NULL;
+	size_t len = 0;
+	int i;
+
+	f = fopen("/proc/self/mountinfo", "r");
+	if (!f)
+		return false;
+
+	while (getline(&line, &len, f) != -1) {
+		for (p = line, i = 0; p && i < 4; i++)
+			p = strchr(p + 1, ' ');
+		if (!p)
+			continue;
+		p2 = strchr(p + 1, ' ');
+		if (!p2)
+			continue;
+		*p2 = '\0';
+		if (strcmp(p + 1, "/") == 0) {
+			// this is '/'.  is it the ramfs?
+			p = strchr(p2 + 1, '-');
+			if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) {
+				fclose(f);
+				return true;
+			}
+		}
+	}
+	fclose(f);
+	return false;
+}
+
+static bool has_fs_type(const struct statfs *fs, __fsword_t magic_val)
 {
 	return (fs->f_type == (__fsword_t)magic_val);
 }
 
+static int pivot_enter(const int oldroot, const int newroot)
+{
+	/* pivot_root into our new root fs */
+	if (pivot_root(".", ".") < 0) {
+		lxcfs_error("pivot_root() syscall failed: %s.\n", strerror(errno));
+		return -1;
+	}
+
+	/*
+	 * At this point the old-root is mounted on top of our new-root.
+	 * To unmounted it we must not be chdir'd into it, so escape back
+	 * to the old-root.
+	 */
+	if (fchdir(oldroot) < 0) {
+		lxcfs_error("%s\n", "Failed to enter old root.");
+		return -1;
+	}
+
+	if (umount2(".", MNT_DETACH) < 0) {
+		lxcfs_error("%s\n", "Failed to detach old root.");
+		return -1;
+	}
+
+	if (fchdir(newroot) < 0) {
+		lxcfs_error("%s\n", "Failed to re-enter new root.");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int chroot_enter()
+{
+	if (mount(ROOTDIR, "/", NULL, MS_REC | MS_BIND, NULL)) {
+		lxcfs_error("Failed to recursively bind-mount %s into /.", ROOTDIR);
+		return -1;
+	}
+
+	if (chroot(".") < 0) {
+		lxcfs_error("Call to chroot() failed: %s.\n", strerror(errno));
+		return -1;
+	}
+
+	if (chdir("/") < 0) {
+		lxcfs_error("Failed to change directory: %s.\n", strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
 static int permute_and_enter(void)
 {
 	int ret = -1, oldroot = -1, newroot = -1;
+	struct statfs sb;
+
+	if (statfs("/", &sb) < 0) {
+		lxcfs_error("%s\n", "Could not stat / mountpoint.");
+		return 1;
+	}
+
+	/* has_fs_type() is not reliable. When the ramfs is a tmpfs it will
+	 * likely report TMPFS_MAGIC. Hence, when it reports no we still check
+	 * /proc/1/mountinfo. */
+	if (has_fs_type(&sb, RAMFS_MAGIC) || is_on_ramfs())
+		return chroot_enter();
 
 	oldroot = open("/", O_DIRECTORY | O_RDONLY);
 	if (oldroot < 0) {
@@ -4178,28 +4282,8 @@ static int permute_and_enter(void)
 		goto err;
 	}
 
-	/* pivot_root into our new root fs */
-	if (pivot_root(".", ".") < 0) {
-		lxcfs_error("pivot_root() syscall failed: %s.\n", strerror(errno));
-		goto err;
-	}
-
-	/*
-	 * At this point the old-root is mounted on top of our new-root.
-	 * To unmounted it we must not be chdir'd into it, so escape back
-	 * to the old-root.
-	 */
-	if (fchdir(oldroot) < 0) {
-		lxcfs_error("%s\n", "Failed to enter old root.");
-		goto err;
-	}
-	if (umount2(".", MNT_DETACH) < 0) {
-		lxcfs_error("%s\n", "Failed to detach old root.");
-		goto err;
-	}
-
-	if (fchdir(newroot) < 0) {
-		lxcfs_error("%s\n", "Failed to re-enter new root.");
+	if (pivot_enter(oldroot, newroot) < 0) {
+		lxcfs_error("%s\n", "Could not perform pivot root.");
 		goto err;
 	}
 
@@ -4216,6 +4300,16 @@ static int permute_and_enter(void)
 /* Prepare our new clean root. */
 static int permute_prepare(void)
 {
+	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) < 0) {
+		lxcfs_error("Failed to remount / private: %s.\n", strerror(errno));
+		return false;
+	}
+
+	if (mount("tmpfs", BASEDIR, "tmpfs", 0, "size=100000,mode=700") < 0) {
+		lxcfs_error("%s\n", "Failed to mount tmpfs over lxcfs cgroup mountpoint.");
+		return false;
+	}
+
 	if (mkdir(ROOTDIR, 0700) < 0 && errno != EEXIST) {
 		lxcfs_error("%s\n", "Failed to create directory for new root.");
 		return -1;
@@ -4270,16 +4364,6 @@ static bool setup_cgfs_dir(void)
 		return false;
 	}
 
-	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) < 0) {
-		lxcfs_error("Failed to remount / private: %s.\n", strerror(errno));
-		return false;
-	}
-
-	if (mount("tmpfs", BASEDIR, "tmpfs", 0, "size=100000,mode=700") < 0) {
-		lxcfs_error("%s\n", "Failed to mount tmpfs over lxcfs cgroup mountpoint.");
-		return false;
-	}
-
 	return true;
 }
 


More information about the lxc-devel mailing list