[lxc-devel] [PATCH v3 3/6] lxc-attach: Detect which namespaces to attach to dynamically

Christian Seiler christian at iwakd.de
Thu May 24 13:55:56 UTC 2012


Use the command interface to contact lxc-start to receive the set of
flags passed to clone() when starting the container. This allows lxc-attach
to determine which namespaces were used for the container and select only
those to attach to.

Signed-off-by: Christian Seiler <christian at iwakd.de>
Cc: Daniel Lezcano <daniel.lezcano at free.fr>
Cc: Serge Hallyn <serge.hallyn at canonical.com>
---
 src/lxc/attach.c     |   42 +++++++++++++++++++++++++++++++++++++-----
 src/lxc/attach.h     |    2 +-
 src/lxc/lxc_attach.c |   16 +++++++++++++++-
 3 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index a95b3d3..37e667f 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -121,13 +121,22 @@ out_error:
 	return NULL;
 }
 
-int lxc_attach_to_ns(pid_t pid)
+int lxc_attach_to_ns(pid_t pid, int which)
 {
 	char path[MAXPATHLEN];
-	char *ns[] = { "pid", "mnt", "net", "ipc", "uts" };
-	const int size = sizeof(ns) / sizeof(char *);
+	/* according to <http://article.gmane.org/gmane.linux.kernel.containers.lxc.devel/1429>,
+	 * the file for user namepsaces in /proc/$pid/ns will be called
+	 * 'user' once the kernel supports it
+	 */
+	static char *ns[] = { "mnt", "pid", "uts", "ipc", "user", "net" };
+	static int flags[] = {
+		CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
+		CLONE_NEWUSER, CLONE_NEWNET
+	};
+	static const int size = sizeof(ns) / sizeof(char *);
 	int fd[size];
-	int i;
+	int i, j, saved_errno;
+
 
 	snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
 	if (access(path, X_OK)) {
@@ -136,16 +145,39 @@ int lxc_attach_to_ns(pid_t pid)
 	}
 
 	for (i = 0; i < size; i++) {
+		/* ignore if we are not supposed to attach to that
+		 * namespace
+		 */
+		if (which != -1 && !(which & flags[i])) {
+			fd[i] = -1;
+			continue;
+		}
+
 		snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
 		fd[i] = open(path, O_RDONLY);
 		if (fd[i] < 0) {
+			saved_errno = errno;
+
+			/* close all already opened file descriptors before
+			 * we return an error, so we don't leak them
+			 */
+			for (j = 0; j < i; j++)
+				close(fd[j]);
+
+			errno = saved_errno;
 			SYSERROR("failed to open '%s'", path);
 			return -1;
 		}
 	}
 
 	for (i = 0; i < size; i++) {
-		if (setns(fd[i], 0)) {
+		if (fd[i] >= 0 && setns(fd[i], 0) != 0) {
+			saved_errno = errno;
+
+			for (j = i; j < size; j++)
+				close(fd[j]);
+
+			errno = saved_errno;
 			SYSERROR("failed to set namespace '%s'", ns[i]);
 			return -1;
 		}
diff --git a/src/lxc/attach.h b/src/lxc/attach.h
index 2d46c83..d96fdae 100644
--- a/src/lxc/attach.h
+++ b/src/lxc/attach.h
@@ -33,7 +33,7 @@ struct lxc_proc_context_info {
 
 extern struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid);
 
-extern int lxc_attach_to_ns(pid_t other_pid);
+extern int lxc_attach_to_ns(pid_t other_pid, int which);
 extern int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx);
 
 #endif
diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
index e4f604b..10d4a64 100644
--- a/src/lxc/lxc_attach.c
+++ b/src/lxc/lxc_attach.c
@@ -51,6 +51,7 @@ static const struct option my_longopts[] = {
 
 static int elevated_privileges = 0;
 static signed long new_personality = -1;
+static int namespace_flags = -1;
 
 static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
@@ -139,11 +140,24 @@ int main(int argc, char *argv[])
 
 	curdir = get_current_dir_name();
 
+	/* determine which namespaces the container was created with
+	 * by asking lxc-start
+	 */
+	if (namespace_flags == -1) {
+		namespace_flags = lxc_get_clone_flags(my_args.name);
+		/* call failed */
+		if (namespace_flags == -1) {
+			ERROR("failed to automatically determine the "
+			      "namespaces which the container unshared");
+			return -1;
+		}
+	}
+
 	/* we need to attach before we fork since certain namespaces
 	 * (such as pid namespaces) only really affect children of the
 	 * current process and not the process itself
 	 */
-	ret = lxc_attach_to_ns(init_pid);
+	ret = lxc_attach_to_ns(init_pid, namespace_flags);
 	if (ret < 0) {
 		ERROR("failed to enter the namespace");
 		return -1;
-- 
1.7.2.5





More information about the lxc-devel mailing list