[lxc-devel] [lxc/master] start: use CLONE_PIDFD

brauner on Github lxc-bot at linuxcontainers.org
Thu May 9 17:43:02 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 610 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190509/94b61294/attachment.bin>
-------------- next part --------------
From 33258b95fc1573b68b3dfae7a1d41696293b828d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 9 May 2019 17:09:51 +0200
Subject: [PATCH 1/2] namespace: support CLONE_PIDFD with lxc_clone()

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/conf.c              | 2 +-
 src/lxc/namespace.c         | 6 +++---
 src/lxc/namespace.h         | 2 +-
 src/lxc/start.c             | 2 +-
 src/lxc/storage/nbd.c       | 2 +-
 src/lxc/tools/lxc_unshare.c | 2 +-
 6 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 2515c881ef..0fbbbfa797 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -4419,7 +4419,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
 	d.p[1] = p[1];
 
 	/* Clone child in new user namespace. */
-	pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
+	pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER, NULL);
 	if (pid < 0) {
 		ERROR("Failed to clone process in new user namespace");
 		goto on_error;
diff --git a/src/lxc/namespace.c b/src/lxc/namespace.c
index e22d9a4bf0..59fba412dd 100644
--- a/src/lxc/namespace.c
+++ b/src/lxc/namespace.c
@@ -54,7 +54,7 @@ static int do_clone(void *arg)
 }
 
 #define __LXC_STACK_SIZE 4096
-pid_t lxc_clone(int (*fn)(void *), void *arg, int flags)
+pid_t lxc_clone(int (*fn)(void *), void *arg, int flags, int *pidfd)
 {
 	size_t stack_size;
 	pid_t ret;
@@ -66,9 +66,9 @@ pid_t lxc_clone(int (*fn)(void *), void *arg, int flags)
 	stack_size = __LXC_STACK_SIZE;
 
 #ifdef __ia64__
-	ret = __clone2(do_clone, stack, stack_size, flags | SIGCHLD, &clone_arg);
+	ret = __clone2(do_clone, stack, stack_size, flags | SIGCHLD, &clone_arg, pidfd);
 #else
-	ret = clone(do_clone, stack + stack_size, flags | SIGCHLD, &clone_arg);
+	ret = clone(do_clone, stack + stack_size, flags | SIGCHLD, &clone_arg, pidfd);
 #endif
 	if (ret < 0)
 		SYSERROR("Failed to clone (%#x)", flags);
diff --git a/src/lxc/namespace.h b/src/lxc/namespace.h
index ab583da76a..f2c2ad82c6 100644
--- a/src/lxc/namespace.h
+++ b/src/lxc/namespace.h
@@ -133,7 +133,7 @@ int clone(int (*fn)(void *), void *child_stack,
  * - should call lxc_raw_getpid():
  *   The child should use lxc_raw_getpid() to retrieve its pid.
  */
-extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags);
+extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags, int *pidfd);
 
 extern int lxc_namespace_2_cloneflag(const char *namespace);
 extern int lxc_namespace_2_ns_idx(const char *namespace);
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 34798292cf..48ba2b4240 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1735,7 +1735,7 @@ static int lxc_spawn(struct lxc_handler *handler)
 		pid_t attacher_pid;
 
 		attacher_pid = lxc_clone(do_share_ns, handler,
-					 CLONE_VFORK | CLONE_VM | CLONE_FILES);
+					 CLONE_VFORK | CLONE_VM | CLONE_FILES, NULL);
 		if (attacher_pid < 0) {
 			SYSERROR(LXC_CLONE_ERROR);
 			goto out_delete_net;
diff --git a/src/lxc/storage/nbd.c b/src/lxc/storage/nbd.c
index ab4f752c9d..dc68ee623e 100644
--- a/src/lxc/storage/nbd.c
+++ b/src/lxc/storage/nbd.c
@@ -266,7 +266,7 @@ static bool clone_attach_nbd(const char *nbd, const char *path)
 	data.nbd = nbd;
 	data.path = path;
 
-	pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID);
+	pid = lxc_clone(do_attach_nbd, &data, CLONE_NEWPID, NULL);
 	if (pid < 0)
 		return false;
 
diff --git a/src/lxc/tools/lxc_unshare.c b/src/lxc/tools/lxc_unshare.c
index 1bc04ce928..421d92c2ad 100644
--- a/src/lxc/tools/lxc_unshare.c
+++ b/src/lxc/tools/lxc_unshare.c
@@ -388,7 +388,7 @@ int main(int argc, char *argv[])
 	start_arg.want_hostname = my_args.want_hostname;
 	start_arg.want_default_mounts = my_args.want_default_mounts;
 
-	pid = lxc_clone(do_start, &start_arg, my_args.flags);
+	pid = lxc_clone(do_start, &start_arg, my_args.flags, NULL);
 	if (pid < 0) {
 		ERROR("Failed to clone");
 		free_ifname_list();

From 33942046c58fe0d4fb74e4fe2896b03f2cb26898 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 9 May 2019 19:40:23 +0200
Subject: [PATCH 2/2] start: use CLONE_PIDFD

Use CLONE_PIDFD when possible.

Note the clone() syscall ignores unknown flags which is usually a design
mistake. However, for us this bug is a feature since we can just pass the flag
along and see whether the kernel has given us a pidfd.

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

diff --git a/src/lxc/start.c b/src/lxc/start.c
index 48ba2b4240..51969697e7 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -406,7 +406,9 @@ static int signal_handler(int fd, uint32_t events, void *data,
 	}
 
 	if (siginfo.ssi_signo == SIGHUP) {
-		if (hdlr->proc_pidfd >= 0)
+		if (hdlr->pidfd >= 0)
+			lxc_raw_pidfd_send_signal(hdlr->pidfd, SIGTERM, NULL, 0);
+		else if (hdlr->proc_pidfd >= 0)
 			lxc_raw_pidfd_send_signal(hdlr->proc_pidfd, SIGTERM, NULL, 0);
 		else
 			kill(hdlr->pid, SIGTERM);
@@ -416,7 +418,10 @@ static int signal_handler(int fd, uint32_t events, void *data,
 	}
 
 	if (siginfo.ssi_signo != SIGCHLD) {
-		if (hdlr->proc_pidfd >= 0)
+		if (hdlr->pidfd >= 0)
+			lxc_raw_pidfd_send_signal(hdlr->pidfd,
+						  siginfo.ssi_signo, NULL, 0);
+		else if (hdlr->proc_pidfd >= 0)
 			lxc_raw_pidfd_send_signal(hdlr->proc_pidfd,
 						  siginfo.ssi_signo, NULL, 0);
 		else
@@ -665,6 +670,8 @@ void lxc_zero_handler(struct lxc_handler *handler)
 
 	handler->pinfd = -1;
 
+	handler->pidfd = -EBADF;
+
 	handler->proc_pidfd = -EBADF;
 
 	handler->sigfd = -1;
@@ -687,6 +694,9 @@ void lxc_free_handler(struct lxc_handler *handler)
 	if (handler->pinfd >= 0)
 		close(handler->pinfd);
 
+	if (handler->pidfd >= 0)
+		close(handler->pidfd);
+
 	if (handler->proc_pidfd >= 0)
 		close(handler->proc_pidfd);
 
@@ -734,6 +744,7 @@ struct lxc_handler *lxc_init_handler(const char *name, struct lxc_conf *conf,
 	handler->conf = conf;
 	handler->lxcpath = lxcpath;
 	handler->pinfd = -1;
+	handler->pidfd = -EBADF;
 	handler->proc_pidfd = -EBADF;
 	handler->sigfd = -EBADF;
 	handler->init_died = false;
@@ -1096,19 +1107,23 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
 
 void lxc_abort(const char *name, struct lxc_handler *handler)
 {
-	int ret, status;
+	int ret = 0;
+	int status;
 
 	lxc_set_state(name, handler, ABORTING);
 
-	if (handler->pid > 0) {
+	if (handler->pidfd > 0)
+		ret = lxc_raw_pidfd_send_signal(handler->pidfd, SIGKILL, NULL, 0);
+	else if (handler->proc_pidfd > 0)
 		ret = lxc_raw_pidfd_send_signal(handler->proc_pidfd, SIGKILL, NULL, 0);
-		if (ret < 0)
-			SYSERROR("Failed to send SIGKILL to %d", handler->pid);
-	}
+	else if (handler->pid > 0)
+		ret = kill(handler->pid, SIGKILL);
+	if (ret < 0)
+		SYSERROR("Failed to send SIGKILL to %d", handler->pid);
 
-	while ((ret = waitpid(-1, &status, 0)) > 0) {
-		;
-	}
+	do {
+		ret = waitpid(-1, &status, 0);
+	} while (ret > 0);
 }
 
 static int do_start(void *data)
@@ -1601,7 +1616,8 @@ static inline int do_share_ns(void *arg)
 
 	flags = handler->ns_on_clone_flags;
 	flags |= CLONE_PARENT;
-	handler->pid = lxc_raw_clone_cb(do_start, handler, flags, NULL);
+	handler->pid = lxc_raw_clone_cb(do_start, handler, CLONE_PIDFD | flags,
+					&handler->pidfd);
 	if (handler->pid < 0)
 		return -1;
 
@@ -1748,7 +1764,8 @@ static int lxc_spawn(struct lxc_handler *handler)
 		}
 	} else {
 		handler->pid = lxc_raw_clone_cb(do_start, handler,
-						handler->ns_on_clone_flags, NULL);
+						CLONE_PIDFD | handler->ns_on_clone_flags,
+						&handler->pidfd);
 	}
 	if (handler->pid < 0) {
 		SYSERROR(LXC_CLONE_ERROR);
@@ -1756,9 +1773,11 @@ static int lxc_spawn(struct lxc_handler *handler)
 	}
 	TRACE("Cloned child process %d", handler->pid);
 
-	handler->proc_pidfd = proc_pidfd_open(handler->pid);
-	if (handler->proc_pidfd < 0 && (errno != ENOSYS))
-		goto out_delete_net;
+	if (handler->pidfd < 0) {
+		handler->proc_pidfd = proc_pidfd_open(handler->pid);
+		if (handler->proc_pidfd < 0 && (errno != ENOSYS))
+			goto out_delete_net;
+	}
 
 	for (i = 0; i < LXC_NS_MAX; i++)
 		if (handler->ns_on_clone_flags & ns_info[i].clone_flag)
diff --git a/src/lxc/start.h b/src/lxc/start.h
index 305782f272..a3a5b4d540 100644
--- a/src/lxc/start.h
+++ b/src/lxc/start.h
@@ -102,6 +102,9 @@ struct lxc_handler {
 	/* The child's pid. */
 	pid_t pid;
 
+	/* The child's pidfd. */
+	int pidfd;
+
 	/*
 	 * File descriptor for the /proc/<pid> directory of the container's
 	 * init process.


More information about the lxc-devel mailing list