[lxc-devel] [lxc/master] start: handle kernels without setns support

brauner on Github lxc-bot at linuxcontainers.org
Thu Mar 1 11:13:56 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 381 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180301/773ea8c2/attachment.bin>
-------------- next part --------------
From 9e84479f4c386fce6253929ce85c891dc4b87e89 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 1 Mar 2018 11:52:49 +0100
Subject: [PATCH 1/2] attach: rename to LXC_ATTACH_TERMINAL

Rename from LXC_ATTACH_ALLOCATE_PTY to LXC_ATTACH_TERMINAL. The latter is
shorter and more generic. I don't want this whole terminology of ptys, ttys,
and consoles to leak through the API.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/attach.c           | 117 +++++++++++++++++++++++----------------------
 src/lxc/attach_options.h   |   2 +-
 src/lxc/tools/lxc_attach.c |   2 +-
 3 files changed, 61 insertions(+), 60 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 241bd3566..9a8a836d5 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -743,7 +743,7 @@ static signed long get_personality(const char *name, const char *lxcpath)
 
 struct attach_clone_payload {
 	int ipc_socket;
-	int pty_fd;
+	int terminal_slave_fd;
 	lxc_attach_options_t *options;
 	struct lxc_proc_context_info *init_ctx;
 	lxc_attach_exec_t exec_function;
@@ -758,9 +758,9 @@ static void lxc_put_attach_clone_payload(struct attach_clone_payload *p)
 		p->ipc_socket = -EBADF;
 	}
 
-	if (p->pty_fd >= 0) {
-		close(p->pty_fd);
-		p->pty_fd = -EBADF;
+	if (p->terminal_slave_fd >= 0) {
+		close(p->terminal_slave_fd);
+		p->terminal_slave_fd = -EBADF;
 	}
 
 	if (p->init_ctx) {
@@ -957,13 +957,13 @@ static int attach_child_main(struct attach_clone_payload *payload)
 		}
 	}
 
-	if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
-		ret = lxc_terminal_prepare_login(payload->pty_fd);
+	if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+		ret = lxc_terminal_prepare_login(payload->terminal_slave_fd);
 		if (ret < 0) {
-			SYSERROR("Failed to prepare pty file descriptor %d", payload->pty_fd);
+			SYSERROR("Failed to prepare terminal file descriptor %d", payload->terminal_slave_fd);
 			goto on_error;
 		}
-		TRACE("Prepared pty file descriptor %d", payload->pty_fd);
+		TRACE("Prepared terminal file descriptor %d", payload->terminal_slave_fd);
 	}
 
 	/* We're done, so we can now do whatever the user intended us to do. */
@@ -974,35 +974,36 @@ static int attach_child_main(struct attach_clone_payload *payload)
 	rexit(EXIT_FAILURE);
 }
 
-static int lxc_attach_pty(struct lxc_conf *conf, struct lxc_terminal *pty)
+static int lxc_attach_terminal(struct lxc_conf *conf,
+			       struct lxc_terminal *terminal)
 {
 	int ret;
 
-	lxc_terminal_init(pty);
+	lxc_terminal_init(terminal);
 
-	ret = lxc_terminal_create(pty);
+	ret = lxc_terminal_create(terminal);
 	if (ret < 0) {
-		SYSERROR("Failed to create pty");
+		SYSERROR("Failed to create terminal");
 		return -1;
 	}
 
 	/* Shift ttys to container. */
-	ret = lxc_terminal_map_ids(conf, pty);
+	ret = lxc_terminal_map_ids(conf, terminal);
 	if (ret < 0) {
-		ERROR("Failed to shift pty");
+		ERROR("Failed to chown terminal");
 		goto on_error;
 	}
 
 	return 0;
 
 on_error:
-	lxc_terminal_delete(pty);
-	lxc_terminal_conf_free(pty);
+	lxc_terminal_delete(terminal);
+	lxc_terminal_conf_free(terminal);
 	return -1;
 }
 
-static int lxc_attach_pty_mainloop_init(struct lxc_terminal *pty,
-					struct lxc_epoll_descr *descr)
+static int lxc_attach_terminal_mainloop_init(struct lxc_terminal *terminal,
+					     struct lxc_epoll_descr *descr)
 {
 	int ret;
 
@@ -1012,7 +1013,7 @@ static int lxc_attach_pty_mainloop_init(struct lxc_terminal *pty,
 		return -1;
 	}
 
-	ret = lxc_terminal_mainloop_add(descr, pty);
+	ret = lxc_terminal_mainloop_add(descr, terminal);
 	if (ret < 0) {
 		ERROR("Failed to add handlers to mainloop");
 		lxc_mainloop_close(descr);
@@ -1022,40 +1023,40 @@ static int lxc_attach_pty_mainloop_init(struct lxc_terminal *pty,
 	return 0;
 }
 
-static inline void lxc_attach_pty_close_master(struct lxc_terminal *pty)
+static inline void lxc_attach_terminal_close_master(struct lxc_terminal *terminal)
 {
-	if (pty->master < 0)
+	if (terminal->master < 0)
 		return;
 
-	close(pty->master);
-	pty->master = -EBADF;
+	close(terminal->master);
+	terminal->master = -EBADF;
 }
 
-static inline void lxc_attach_pty_close_slave(struct lxc_terminal *pty)
+static inline void lxc_attach_terminal_close_slave(struct lxc_terminal *terminal)
 {
-	if (pty->slave < 0)
+	if (terminal->slave < 0)
 		return;
 
-	close(pty->slave);
-	pty->slave = -EBADF;
+	close(terminal->slave);
+	terminal->slave = -EBADF;
 }
 
-static inline void lxc_attach_pty_close_peer(struct lxc_terminal *pty)
+static inline void lxc_attach_terminal_close_peer(struct lxc_terminal *terminal)
 {
-	if (pty->peer < 0)
+	if (terminal->peer < 0)
 		return;
 
-	close(pty->peer);
-	pty->peer = -EBADF;
+	close(terminal->peer);
+	terminal->peer = -EBADF;
 }
 
-static inline void lxc_attach_pty_close_log(struct lxc_terminal *pty)
+static inline void lxc_attach_terminal_close_log(struct lxc_terminal *terminal)
 {
-	if (pty->log_fd < 0)
+	if (terminal->log_fd < 0)
 		return;
 
-	close(pty->log_fd);
-	pty->log_fd = -EBADF;
+	close(terminal->log_fd);
+	terminal->log_fd = -EBADF;
 }
 
 int lxc_attach(const char *name, const char *lxcpath,
@@ -1068,7 +1069,7 @@ int lxc_attach(const char *name, const char *lxcpath,
 	signed long personality;
 	pid_t attached_pid, init_pid, pid;
 	struct lxc_proc_context_info *init_ctx;
-	struct lxc_terminal pty;
+	struct lxc_terminal terminal;
 	struct lxc_conf *conf;
 	struct attach_clone_payload payload = {0};
 
@@ -1187,18 +1188,18 @@ int lxc_attach(const char *name, const char *lxcpath,
 		return -1;
 	}
 
-	if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
-		ret = lxc_attach_pty(conf, &pty);
+	if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+		ret = lxc_attach_terminal(conf, &terminal);
 		if (ret < 0) {
-			ERROR("Failed to allocate pty");
+			ERROR("Failed to setup new terminal");
 			free(cwd);
 			lxc_proc_put_context_info(init_ctx);
 			return -1;
 		}
 
-		pty.log_fd = options->log_fd;
+		terminal.log_fd = options->log_fd;
 	} else {
-		lxc_terminal_init(&pty);
+		lxc_terminal_init(&terminal);
 	}
 
 	/* Create a socket pair for IPC communication; set SOCK_CLOEXEC in order
@@ -1266,8 +1267,8 @@ int lxc_attach(const char *name, const char *lxcpath,
 		close(ipc_sockets[1]);
 		free(cwd);
 		lxc_proc_close_ns_fd(init_ctx);
-		if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
-			lxc_attach_pty_close_slave(&pty);
+		if (options->attach_flags & LXC_ATTACH_TERMINAL)
+			lxc_attach_terminal_close_slave(&terminal);
 
 		/* Attach to cgroup, if requested. */
 		if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
@@ -1291,11 +1292,11 @@ int lxc_attach(const char *name, const char *lxcpath,
 				goto on_error;
 		}
 
-		if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
-			ret = lxc_attach_pty_mainloop_init(&pty, &descr);
+		if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+			ret = lxc_attach_terminal_mainloop_init(&terminal, &descr);
 			if (ret < 0)
 				goto on_error;
-			TRACE("Initialized pty mainloop");
+			TRACE("Initialized terminal mainloop");
 		}
 
 		/* Let the child process know to go ahead. */
@@ -1364,7 +1365,7 @@ int lxc_attach(const char *name, const char *lxcpath,
 
 		ret_parent = 0;
 		to_cleanup_pid = -1;
-		if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
+		if (options->attach_flags & LXC_ATTACH_TERMINAL) {
 			ret = lxc_mainloop(&descr, -1);
 			if (ret < 0) {
 				ret_parent = -1;
@@ -1373,7 +1374,7 @@ int lxc_attach(const char *name, const char *lxcpath,
 		}
 
 	close_mainloop:
-		if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
+		if (options->attach_flags & LXC_ATTACH_TERMINAL)
 			lxc_mainloop_close(&descr);
 
 	on_error:
@@ -1385,9 +1386,9 @@ int lxc_attach(const char *name, const char *lxcpath,
 		if (to_cleanup_pid > 0)
 			(void)wait_for_pid(to_cleanup_pid);
 
-		if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
-			lxc_terminal_delete(&pty);
-			lxc_terminal_conf_free(&pty);
+		if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+			lxc_terminal_delete(&terminal);
+			lxc_terminal_conf_free(&terminal);
 		}
 		lxc_proc_put_context_info(init_ctx);
 		return ret_parent;
@@ -1396,10 +1397,10 @@ int lxc_attach(const char *name, const char *lxcpath,
 	/* close unneeded file descriptors */
 	close(ipc_sockets[0]);
 	ipc_sockets[0] = -EBADF;
-	if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY) {
-		lxc_attach_pty_close_master(&pty);
-		lxc_attach_pty_close_peer(&pty);
-		lxc_attach_pty_close_log(&pty);
+	if (options->attach_flags & LXC_ATTACH_TERMINAL) {
+		lxc_attach_terminal_close_master(&terminal);
+		lxc_attach_terminal_close_peer(&terminal);
+		lxc_attach_terminal_close_log(&terminal);
 	}
 
 	/* Wait for the parent to have setup cgroups. */
@@ -1440,7 +1441,7 @@ int lxc_attach(const char *name, const char *lxcpath,
 	payload.ipc_socket = ipc_sockets[1];
 	payload.options = options;
 	payload.init_ctx = init_ctx;
-	payload.pty_fd = pty.slave;
+	payload.terminal_slave_fd = terminal.slave;
 	payload.exec_function = exec_function;
 	payload.exec_payload = exec_payload;
 
@@ -1458,8 +1459,8 @@ int lxc_attach(const char *name, const char *lxcpath,
 			ERROR("Failed to exec");
 		_exit(EXIT_FAILURE);
 	}
-	if (options->attach_flags & LXC_ATTACH_ALLOCATE_PTY)
-		lxc_attach_pty_close_slave(&pty);
+	if (options->attach_flags & LXC_ATTACH_TERMINAL)
+		lxc_attach_terminal_close_slave(&terminal);
 
 	/* Tell grandparent the pid of the pid of the newly created child. */
 	ret = lxc_write_nointr(ipc_sockets[1], &pid, sizeof(pid));
diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h
index 1e64e4abf..193fd7e7d 100644
--- a/src/lxc/attach_options.h
+++ b/src/lxc/attach_options.h
@@ -51,7 +51,7 @@ enum {
 	LXC_ATTACH_LSM_NOW               = 0x00020000, /*!< FIXME: unknown */
 	/* Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges. */
 	LXC_ATTACH_NO_NEW_PRIVS		 = 0x00040000, /*!< PR_SET_NO_NEW_PRIVS */
-	LXC_ATTACH_ALLOCATE_PTY          = 0x00080000, /*!< Allocate new pty for attached process. */
+	LXC_ATTACH_TERMINAL              = 0x00080000, /*!< Allocate new terminal for attached process. */
 
 	/* We have 16 bits for things that are on by default and 16 bits that
 	 * are off by default, that should be sufficient to keep binary
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index 087a46f68..74b2829d6 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -321,7 +321,7 @@ int main(int argc, char *argv[])
 	if (elevated_privileges)
 		attach_options.attach_flags &= ~(elevated_privileges);
 	if (stdfd_is_pty())
-		attach_options.attach_flags |= LXC_ATTACH_ALLOCATE_PTY;
+		attach_options.attach_flags |= LXC_ATTACH_TERMINAL;
 	attach_options.namespaces = namespace_flags;
 	attach_options.personality = new_personality;
 	attach_options.env_policy = env_policy;

From 4cb53844bc9a591704a10606de1107f4f67b90dd Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 1 Mar 2018 12:12:50 +0100
Subject: [PATCH 2/2] start: handle kernels without setns support

Closes #1390.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/start.c | 88 +++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 60 insertions(+), 28 deletions(-)

diff --git a/src/lxc/start.c b/src/lxc/start.c
index eb7331f8a..4e2f8a433 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -142,11 +142,31 @@ static void lxc_put_nsfds(struct lxc_handler *handler)
 	}
 }
 
-/* lxc_preserve_namespaces: open /proc/@pid/ns/@ns for each namespace specified
- * in ns_clone_flags.
+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;
+}
+
+/* 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 lxc_preserve_namespaces(struct lxc_handler *handler, int ns_clone_flags, pid_t pid)
+static bool lxc_try_preserve_namespaces(struct lxc_handler *handler,
+					int ns_clone_flags, pid_t pid)
 {
 	int i;
 
@@ -154,27 +174,32 @@ static bool lxc_preserve_namespaces(struct lxc_handler *handler, int ns_clone_fl
 		handler->nsfd[i] = -EBADF;
 
 	for (i = 0; i < LXC_NS_MAX; i++) {
+		int fd;
+
 		if ((ns_clone_flags & ns_info[i].clone_flag) == 0)
 			continue;
 
-		handler->nsfd[i] = lxc_preserve_ns(pid, ns_info[i].proc_name);
-		if (handler->nsfd[i] < 0)
-			goto error;
+		fd = lxc_try_preserve_ns(pid, ns_info[i].proc_name);
+		if (fd < 0) {
+			handler->nsfd[i] = -EBADF;
 
-		DEBUG("Preserved %s namespace via fd %d", ns_info[i].proc_name, handler->nsfd[i]);
+			/* 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]);
 	}
 
 	return true;
-
-error:
-	if (errno == ENOENT)
-		SYSERROR("Kernel does not support attaching to %s namespaces",
-			 ns_info[i].proc_name);
-	else
-		SYSERROR("Failed to open file descriptor for %s namespace",
-			 ns_info[i].proc_name);
-	lxc_put_nsfds(handler);
-	return false;
 }
 
 static int match_fd(int fd)
@@ -1590,7 +1615,7 @@ static int lxc_spawn(struct lxc_handler *handler)
 		if (handler->ns_on_clone_flags & ns_info[i].clone_flag)
 			INFO("Cloned %s", ns_info[i].flag_name);
 
-	if (!lxc_preserve_namespaces(handler, handler->ns_on_clone_flags, handler->pid)) {
+	if (!lxc_try_preserve_namespaces(handler, handler->ns_on_clone_flags, handler->pid)) {
 		ERROR("Failed to preserve cloned namespaces for lxc.hook.stop");
 		goto out_delete_net;
 	}
@@ -1634,13 +1659,16 @@ static int lxc_spawn(struct lxc_handler *handler)
 		goto out_delete_net;
 
 	/* Now we're ready to preserve the network namespace */
-	ret = lxc_preserve_ns(handler->pid, "net");
+	ret = lxc_try_preserve_ns(handler->pid, "net");
 	if (ret < 0) {
-		ERROR("%s - Failed to preserve net namespace", strerror(errno));
-		goto out_delete_net;
+		if (ret != -EOPNOTSUPP) {
+			ERROR("%s - Failed to preserve net namespace", strerror(errno));
+			goto out_delete_net;
+		}
+	} else {
+		handler->nsfd[LXC_NS_NET] = ret;
+		DEBUG("Preserved net namespace via fd %d", ret);
 	}
-	handler->nsfd[LXC_NS_NET] = ret;
-	DEBUG("Preserved net namespace via fd %d", ret);
 
 	/* Create the network configuration. */
 	if (handler->ns_clone_flags & CLONE_NEWNET) {
@@ -1703,13 +1731,17 @@ static int lxc_spawn(struct lxc_handler *handler)
 
 	if (handler->ns_clone_flags & CLONE_NEWCGROUP) {
 		/* Now we're ready to preserve the cgroup namespace */
-		ret = lxc_preserve_ns(handler->pid, "cgroup");
+		ret = lxc_try_preserve_ns(handler->pid, "cgroup");
 		if (ret < 0) {
-			ERROR("%s - Failed to preserve cgroup namespace", strerror(errno));
-			goto out_delete_net;
+			if (ret != -EOPNOTSUPP) {
+				ERROR("%s - Failed to preserve cgroup namespace",
+				      strerror(errno));
+				goto out_delete_net;
+			}
+		} else {
+			handler->nsfd[LXC_NS_CGROUP] = ret;
+			DEBUG("Preserved cgroup namespace via fd %d", ret);
 		}
-		handler->nsfd[LXC_NS_CGROUP] = ret;
-		DEBUG("Preserved cgroup namespace via fd %d", ret);
 	}
 
 	ret = snprintf(pidstr, 20, "%d", handler->pid);


More information about the lxc-devel mailing list