[lxc-devel] [lxc/master] attach: handle namespace inheritance

brauner on Github lxc-bot at linuxcontainers.org
Wed Nov 1 09:47:06 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 673 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171101/d605edd4/attachment.bin>
-------------- next part --------------
From 683a9ee930a283d0a73869909ec719fe589ccfe9 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 1 Nov 2017 10:44:18 +0100
Subject: [PATCH] attach: handle namespace inheritance

We need to have lxc_attach() distinguish between a caller specifying specific
namespaces to attach to and a caller not requesting specific namespaces. The
latter is taken by lxc_attach() to mean that all namespaces will be attached.
This also needs to include all inherited namespaces.

Closes #1890.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/attach.c | 84 +++++++++++++++++++++++++++++++++-----------------------
 src/lxc/attach.h |  6 ++++
 2 files changed, 56 insertions(+), 34 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 5a42cc29e..6d36d9b69 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -300,10 +300,11 @@ static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
 	return ret;
 }
 
-static int lxc_attach_to_ns(pid_t pid, int which)
+static int lxc_attach_to_ns(pid_t pid, int which, bool attach_all_namespaces)
 {
 	int fd[LXC_NS_MAX];
 	int i, j, ret, saved_errno;
+	pid_t self;
 
 	ret = access("/proc/self/ns", X_OK);
 	if (ret) {
@@ -311,48 +312,55 @@ static int lxc_attach_to_ns(pid_t pid, int which)
 		return -1;
 	}
 
+	self = getpid();
 	for (i = 0; i < LXC_NS_MAX; i++) {
-		fd[i] = -EINVAL;
-
-		/* Ignore if we are not supposed to attach to that namespace. */
-		if (which != -1 && !(which & ns_info[i].clone_flag)) {
-			/* We likely inherited the namespace from someone. We
-			 * need to check whether we are already in the same
-			 * namespace. If we are then there's nothing for us to
-			 * do. If we are not then we need to attach to it.
-			 */
-			fd[i] = in_same_namespace(getpid(), pid, ns_info[i].proc_name);
-			/* we are in the same namespace */
-			if (fd[i] == -EINVAL) {
-				DEBUG("Inheriting %s namespace from %d",
-				      ns_info[i].proc_name, pid);
-				continue;
-			}
-		}
+		/* Ignore if we are not supposed to attach to that namespace and
+		 * if the caller did specify specific namespaces to attach to.
+		 */
+		fd[i] = -1;
+		if (which != -1 && !(which & ns_info[i].clone_flag) &&
+		    !attach_all_namespaces)
+			continue;
 
-		if (fd[i] == -EINVAL)
+		/* If the container was clone()ed with that flag there's likely
+		 * no need to check if we are in the same namespace so simply
+		 * preserve the namespace.
+		 */
+		if ((which & ns_info[i].clone_flag))
 			fd[i] = lxc_preserve_ns(pid, ns_info[i].proc_name);
-		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]);
+		else
+			fd[i] = in_same_namespace(self, pid, ns_info[i].proc_name);
+		if (fd[i] >= 0)
+			continue;
 
-			errno = saved_errno;
-			SYSERROR("Failed to attach to %s namespace of %d",
-				 ns_info[i].proc_name, pid);
-			return -1;
+		/* This is the caller's own namespaces. */
+		if (fd[i] == -EINVAL) {
+			DEBUG("Inheriting %s namespace from %d",
+			      ns_info[i].proc_name, pid);
+			continue;
 		}
+
+		/* We failed to preserve the namespace. */
+		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 attach to %s namespace of %d",
+			 ns_info[i].proc_name, pid);
+		return -1;
 	}
 
 	for (i = 0; i < LXC_NS_MAX; i++) {
 		if (fd[i] < 0)
 			continue;
 
-		if (setns(fd[i], 0) < 0) {
+		ret = setns(fd[i], ns_info[i].clone_flag);
+		if (ret < 0) {
 			saved_errno = errno;
 
 			for (j = i; j < LXC_NS_MAX; j++)
@@ -365,7 +373,6 @@ static int lxc_attach_to_ns(pid_t pid, int which)
 		}
 
 		DEBUG("Attached to %s namespace of %d", ns_info[i].proc_name, pid);
-
 		close(fd[i]);
 	}
 
@@ -889,6 +896,7 @@ int lxc_attach(const char *name, const char *lxcpath,
 	/* Determine which namespaces the container was created with
 	 * by asking lxc-start, if necessary.
 	 */
+	init_ctx->attach_all_namespaces = false;
 	if (options->namespaces == -1) {
 		options->namespaces = lxc_cmd_get_clone_flags(name, lxcpath);
 		/* call failed */
@@ -899,6 +907,13 @@ int lxc_attach(const char *name, const char *lxcpath,
 			lxc_proc_put_context_info(init_ctx);
 			return -1;
 		}
+
+		/* In case callers didn't specify specific namespaces to attach
+		 * to we retrieve the flags the container was clone()ed.
+		 * However, these flags do not include inherited namespaces. But
+		 * we need to attach to those to.
+		 */
+		init_ctx->attach_all_namespaces = true;
 	}
 
 	/* Create a socket pair for IPC communication; set SOCK_CLOEXEC in order
@@ -1134,7 +1149,8 @@ int lxc_attach(const char *name, const char *lxcpath,
 	/* Attach now, create another subprocess later, since pid namespaces
 	 * only really affect the children of the current process.
 	 */
-	ret = lxc_attach_to_ns(init_pid, options->namespaces);
+	ret = lxc_attach_to_ns(init_pid, options->namespaces,
+			       init_ctx->attach_all_namespaces);
 	if (ret < 0) {
 		ERROR("Failed to enter namespaces.");
 		shutdown(ipc_sockets[1], SHUT_RDWR);
diff --git a/src/lxc/attach.h b/src/lxc/attach.h
index fb6bc5a07..4256fb1e2 100644
--- a/src/lxc/attach.h
+++ b/src/lxc/attach.h
@@ -24,6 +24,7 @@
 #ifndef __LXC_ATTACH_H
 #define __LXC_ATTACH_H
 
+#include <stdbool.h>
 #include <lxc/attach_options.h>
 #include <sys/types.h>
 
@@ -34,6 +35,11 @@ struct lxc_proc_context_info {
 	struct lxc_container *container;
 	signed long personality;
 	unsigned long long capability_mask;
+
+	/* Indicator whether we are supposed to attach to all
+	 * namespaces of the container.
+	 */
+	bool attach_all_namespaces;
 };
 
 extern int lxc_attach(const char *name, const char *lxcpath,


More information about the lxc-devel mailing list