File pivot-root_shared.patch of Package lxc

From cc28d0b0a66bd956645dc7b8fc85b917711f2472 Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serge.hallyn@canonical.com>
Date: Wed, 19 Dec 2012 23:58:44 -0600
Subject: [PATCH] Support MS_SHARED /
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

(I'll be out until Jan 2, but in the meantime, here is hopefully a
little newyears gift - this seems to allow lxc-start with / being
MS_SHARED on the host)

When / is MS_SHARED (for instance with f18 and modern arch), lxc-start
fails on pivot_root.  The kernel enforces that, when doing pivot_root,
the parent of current->fs->root (as well as the new root and the putold
location) not be MS_SHARED.

To work around this, check /proc/self/mountinfo for a 'shared:' in
the '/' line.  If it is there, then create a tiny MS_SLAVE tmpfs dir to
serve as parent of /, recursively bind mount / into /root under that dir,
make it rslave, and chroot into it.

Tested with ubuntu raring image after doing 'mount --make-rshared /'.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
---
 src/lxc/conf.c  |  117 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/lxc/conf.h  |    3 ++
 src/lxc/start.c |    8 ++++
 3 files changed, 125 insertions(+), 3 deletions(-)

Index: lxc-0.7.5/src/lxc/conf.c
===================================================================
--- lxc-0.7.5.orig/src/lxc/conf.c
+++ lxc-0.7.5/src/lxc/conf.c
@@ -716,8 +716,112 @@ static int setup_rootfs_pivot_root(const
 	return 0;
 }
 
-static int setup_rootfs(const struct lxc_rootfs *rootfs)
+/*
+ * Detect whether / is mounted MS_SHARED.  The only way I know of to
+ * check that is through /proc/self/mountinfo.
+ * I'm only checking for /.  If the container rootfs or mount location
+ * is MS_SHARED, but not '/', then you're out of luck - figuring that
+ * out would be too much work to be worth it.
+ */
+#define LINELEN 4096
+int detect_shared_rootfs(void)
 {
+	char buf[LINELEN], *p;
+	FILE *f;
+	int i;
+	char *p2;
+
+	f = fopen("/proc/self/mountinfo", "r");
+	if (!f)
+		return 0;
+	while ((p = fgets(buf, LINELEN, f))) {
+		INFO("looking at .%s.", p);
+		for (p = buf, i=0; p && i < 4; i++)
+			p = index(p+1, ' ');
+		if (!p)
+			continue;
+		p2 = index(p+1, ' ');
+		if (!p2)
+			continue;
+		*p2 = '\0';
+		INFO("now p is .%s.", p);
+		if (strcmp(p+1, "/") == 0) {
+			// this is '/'.  is it shared?
+			p = index(p2+1, ' ');
+			if (strstr(p, "shared:"))
+				return 1;
+		}
+	}
+	fclose(f);
+	return 0;
+}
+
+/*
+ * I'll forgive you for asking whether all of this is needed :)  The
+ * answer is yes.
+ * pivot_root will fail if the new root, the put_old dir, or the parent
+ * of current->fs->root are MS_SHARED.  (parent of current->fs_root may
+ * or may not be current->fs_root - if we assumed it always was, we could
+ * just mount --make-rslave /).  So,
+ *    1. mount a tiny tmpfs to be parent of current->fs->root.
+ *    2. make that MS_SLAVE
+ *    3. make a 'root' directory under that
+ *    4. mount --rbind / under the $tinyroot/root.
+ *    5. make that rslave
+ *    6. chdir and chroot into $tinyroot/root
+ *    7. $tinyroot will be unmounted by our parent in start.c
+ */
+static int chroot_into_slave(struct lxc_conf *conf)
+{
+	char path[MAXPATHLEN];
+	const char *destpath = conf->rootfs.mount;
+	int ret;
+
+	if (mount(destpath, destpath, NULL, MS_BIND, 0)) {
+		SYSERROR("failed to mount %s bind", destpath);
+		return -1;
+	}
+	if (mount("", destpath, NULL, MS_SLAVE, 0)) {
+		SYSERROR("failed to make %s slave", destpath);
+		return -1;
+	}
+	if (mount("none", destpath, "tmpfs", 0, "size=10000")) {
+		SYSERROR("Failed to mount tmpfs / at %s", destpath);
+		return -1;
+	}
+	ret = snprintf(path, MAXPATHLEN, "%s/root", destpath);
+	if (ret < 0 || ret >= MAXPATHLEN) {
+		ERROR("out of memory making root path");
+		return -1;
+	}
+	if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
+		SYSERROR("Failed to create /dev/pts in container");
+		return -1;
+	}
+	if (mount("/", path, NULL, MS_BIND|MS_REC, 0)) {
+		SYSERROR("Failed to rbind mount / to %s", path);
+		return -1;
+	}
+	if (mount("", destpath, NULL, MS_SLAVE|MS_REC, 0)) {
+		SYSERROR("Failed to make tmp-/ at %s rslave", path);
+		return -1;
+	}
+	if (chdir(path)) {
+		SYSERROR("Failed to chdir into tmp-/");
+		return -1;
+	}
+	if (chroot(path)) {
+		SYSERROR("Failed to chroot into tmp-/");
+		return -1;
+	}
+	INFO("Chrooted into tmp-/ at %s\n", path);
+	return 0;
+}
+
+static int setup_rootfs(struct lxc_conf *conf)
+{
+	const struct lxc_rootfs *rootfs = &conf->rootfs;
+
 	if (!rootfs->path)
 		return 0;
 
@@ -727,6 +831,13 @@ static int setup_rootfs(const struct lxc
 		return -1;
 	}
 
+	if (detect_shared_rootfs()) {
+		if (chroot_into_slave(conf)) {
+			ERROR("Failed to chroot into slave /");
+			return -1;
+		}
+	}
+
 	if (mount_rootfs(rootfs->path, rootfs->mount)) {
 		ERROR("failed to mount rootfs");
 		return -1;
@@ -848,7 +959,7 @@ static int setup_console(const struct lx
 	return 0;
 }
 
-static int setup_cgroup(const char *name, struct lxc_list *cgroups)
+int setup_cgroup(const char *name, struct lxc_list *cgroups)
 {
 	struct lxc_list *iterator;
 	struct lxc_cgroup *cg;
@@ -1846,7 +1957,7 @@ int lxc_setup(const char *name, struct l
 		return -1;
 	}
 
-	if (setup_rootfs(&lxc_conf->rootfs)) {
+	if (setup_rootfs(lxc_conf)) {
 		ERROR("failed to setup rootfs for '%s'", name);
 		return -1;
 	}
Index: lxc-0.7.5/src/lxc/conf.h
===================================================================
--- lxc-0.7.5.orig/src/lxc/conf.h
+++ lxc-0.7.5/src/lxc/conf.h
@@ -227,6 +227,9 @@ extern int lxc_find_gateway_addresses(st
 extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
 extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
 
+extern int setup_cgroup(const char *name, struct lxc_list *cgroups);
+extern int detect_shared_rootfs(void);
+
 /*
  * Configure the container from inside
  */
Index: lxc-0.7.5/src/lxc/start.c
===================================================================
--- lxc-0.7.5.orig/src/lxc/start.c
+++ lxc-0.7.5/src/lxc/start.c
@@ -535,6 +535,14 @@ int lxc_spawn(struct lxc_handler *handle
 	if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CONFIGURE))
 		return -1;
 
+	if (detect_shared_rootfs())
+		umount2(handler->conf->rootfs.mount, MNT_DETACH);
+
+	if (setup_cgroup(name, &handler->conf->cgroup)) {
+		ERROR("failed to setup the cgroups for '%s'", name);
+		goto out_delete_net;
+	}
+
 	if (handler->ops->post_start(handler, handler->data))
 		goto out_abort;
 
From 859a6da0fac5d214230f8a52777277b5147532fb Mon Sep 17 00:00:00 2001
From: Natanael Copa <ncopa@alpinelinux.org>
Date: Tue, 25 Dec 2012 10:53:50 +0100
Subject: [PATCH] define MS_SHARED if needed
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fixes build on uClibc.

Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
---
 src/lxc/conf.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 96940b3..c82e759 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -87,6 +87,10 @@ lxc_log_define(lxc_conf, lxc);
 #define MNT_DETACH 2
 #endif
 
+#ifndef MS_SLAVE
+#define MS_SLAVE (1<<19)
+#endif
+
 #ifndef MS_RELATIME
 #define MS_RELATIME (1 << 21)
 #endif
-- 
1.7.10.4

openSUSE Build Service is sponsored by