[lxc-devel] [lxc/stable-1.0] start: enable pre-setns() kernels

brauner on Github lxc-bot at linuxcontainers.org
Mon May 28 11:13:39 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 473 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180528/fa4e608a/attachment.bin>
-------------- next part --------------
From 7479b03e9aeaa0de64e29f890c08eed4094982d7 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 28 May 2018 13:12:23 +0200
Subject: [PATCH] start: enable pre-setns() kernels

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/start.c | 105 +++++++++++++++++++++++++++++++-------------------------
 src/lxc/utils.c |  21 ++++++++++++
 src/lxc/utils.h |   2 ++
 3 files changed, 82 insertions(+), 46 deletions(-)

diff --git a/src/lxc/start.c b/src/lxc/start.c
index 9d148dae3..df0f562a2 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -106,62 +106,77 @@ static void print_top_failing_dir(const char *path)
 	}
 }
 
-static void close_ns(int ns_fd[LXC_NS_MAX]) {
+static void lxc_put_nsfds(struct lxc_handler *handler)
+{
 	int i;
 
 	for (i = 0; i < LXC_NS_MAX; i++) {
-		if (ns_fd[i] > -1) {
-			close(ns_fd[i]);
-			ns_fd[i] = -1;
+		if (handler->nsfd[i] < 0)
+			continue;
+
+		close(handler->nsfd[i]);
+		handler->nsfd[i] = -EBADF;
+	}
+}
+
+static int lxc_try_preserve_ns(const int pid, const char *ns)
+{
+	int fd;
+
+	fd = lxc_preserve_ns(pid, ns);
+	if (fd < 0) {
+		if (errno != ENOENT) {
+			SYSERROR("Failed to preserve %s namespace", ns);
+			return -EINVAL;
 		}
+
+		WARN("%s - Kernel does not support preserving %s namespaces",
+		     strerror(errno), ns);
+		return -EOPNOTSUPP;
 	}
+
+	return fd;
 }
 
-/*
- * preserve_ns: open /proc/@pid/ns/@ns for each namespace specified
- * in clone_flags.
- * Return true on success, false on failure.  On failure, leave an error
- * message in *errmsg, which caller must free.
+/* lxc_try_preserve_namespaces: open /proc/@pid/ns/@ns for each namespace
+ * specified in ns_clone_flags.
+ * Return true on success, false on failure.
  */
-static
-bool preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid, char **errmsg) {
-	int i, ret;
-	char path[MAXPATHLEN];
+static bool lxc_try_preserve_namespaces(struct lxc_handler *handler,
+					int ns_clone_flags, pid_t pid)
+{
+	int i;
 
 	for (i = 0; i < LXC_NS_MAX; i++)
-		ns_fd[i] = -1;
-
-	snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
-	if (access(path, X_OK)) {
-		if (asprintf(errmsg, "Kernel does not support setns.") == -1)
-			*errmsg = NULL;
-		return false;
-	}
+		handler->nsfd[i] = -EBADF;
 
 	for (i = 0; i < LXC_NS_MAX; i++) {
-		if ((clone_flags & ns_info[i].clone_flag) == 0)
+		int fd;
+
+		if ((ns_clone_flags & ns_info[i].clone_flag) == 0)
 			continue;
-		snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid,
-		         ns_info[i].proc_name);
-		ns_fd[i] = open(path, O_RDONLY | O_CLOEXEC);
-		if (ns_fd[i] < 0)
-			goto error;
-	}
 
-	return true;
+		fd = lxc_try_preserve_ns(pid, ns_info[i].proc_name);
+		if (fd < 0) {
+			handler->nsfd[i] = -EBADF;
 
-error:
-	if (errno == ENOENT) {
-		ret = asprintf(errmsg, "Kernel does not support setns for %s",
-			ns_info[i].proc_name);
-	} else {
-		ret = asprintf(errmsg, "Failed to open %s: %s",
-			path, strerror(errno));
+			/* Do not fail to start container on kernels that do
+			 * not support interacting with namespaces through
+			 * /proc.
+			 */
+			if (fd == -EOPNOTSUPP)
+				continue;
+
+			lxc_put_nsfds(handler);
+			return false;
+		}
+
+		handler->nsfd[i] = fd;
+		DEBUG("Preserved %s namespace via fd %d", ns_info[i].proc_name,
+		      handler->nsfd[i]);
 	}
-	if (ret == -1)
-		*errmsg = NULL;
-	close_ns(ns_fd);
-	return false;
+
+	return true;
 }
 
 static int attach_ns(const int ns_fd[LXC_NS_MAX]) {
@@ -931,9 +946,8 @@ static int lxc_spawn(struct lxc_handler *handler)
 			INFO("failed to pin the container's rootfs");
 	}
 
-	if (!preserve_ns(saved_ns_fd, preserve_mask, getpid(), &errmsg)) {
-		SYSERROR("Failed to preserve requested namespaces: %s",
-			errmsg ? errmsg : "(Out of memory)");
+	if (!lxc_try_preserve_namespaces(saved_ns_fd, preserve_mask, getpid())) {
+		SYSERROR("Failed to preserve requested namespaces");
 		free(errmsg);
 		goto out_delete_net;
 	}
@@ -959,9 +973,8 @@ static int lxc_spawn(struct lxc_handler *handler)
 		goto out_delete_net;
 	}
 
-	if (!preserve_ns(handler->nsfd, handler->clone_flags | preserve_mask, handler->pid, &errmsg)) {
-		INFO("Failed to store namespace references for stop hook: %s",
-			errmsg ? errmsg : "(Out of memory)");
+	if (!lxc_try_preserve_namespaces(handler->nsfd, handler->clone_flags | preserve_mask, handler->pid)) {
+		INFO("Failed to store namespace references for stop hook");
 		free(errmsg);
 	}
 
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 97892ad1e..677711818 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1392,3 +1392,24 @@ int set_stdfds(int fd)
 
 	return 0;
 }
+
+int lxc_preserve_ns(const int pid, const char *ns)
+{
+	int ret;
+/* 5 /proc + 21 /int_as_str + 3 /ns + 20 /NS_NAME + 1 \0 */
+#define __NS_PATH_LEN 50
+	char path[__NS_PATH_LEN];
+
+	/* This way we can use this function to also check whether namespaces
+	 * are supported by the kernel by passing in the NULL or the empty
+	 * string.
+	 */
+	ret = snprintf(path, __NS_PATH_LEN, "/proc/%d/ns%s%s", pid,
+		       !ns || strcmp(ns, "") == 0 ? "" : "/",
+		       !ns || strcmp(ns, "") == 0 ? "" : ns);
+	errno = EFBIG;
+	if (ret < 0 || (size_t)ret >= __NS_PATH_LEN)
+		return -EFBIG;
+
+	return open(path, O_RDONLY | O_CLOEXEC);
+}
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 8859eeb74..1c53d1c99 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -319,4 +319,6 @@ int null_stdfds(void);
 int safe_mount(const char *src, const char *dest, const char *fstype,
 		unsigned long flags, const void *data, const char *rootfs);
 int set_stdfds(int fd);
+int lxc_preserve_ns(const int pid, const char *ns);
+
 #endif /* __LXC_UTILS_H */


More information about the lxc-devel mailing list