[lxc-devel] [lxc/master] signal child in case of failure when running in userns

tych0 on Github lxc-bot at linuxcontainers.org
Thu Feb 8 09:07:59 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1106 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180208/08b4cc56/attachment.bin>
-------------- next part --------------
From 59e9407dcfade3b967191db69772db3852342fa3 Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho at tycho.ws>
Date: Thu, 8 Feb 2018 09:52:05 +0100
Subject: [PATCH] signal child in case of failure when running in userns

In the case where we fail (e.g. if there are no subuids for the current
user) to run something in the userns, let's signal the child so that they
can exit. Simply closing the pipe causes a hang:

int main(void)
{
	int p[2];
	pid_t pid;
	int status;

	if (pipe(p) < 0) {
		perror("pipe");
		return 1;
	}

	pid = fork();
	if (pid < 0) {
		perror("fork");
		return 1;
	}

	if (pid == 0) {
		char c;

		if (read(p[0], &c, 1) != 1) {
			perror("read");
			exit(1);
		}

		exit(0);
	}

	close(p[1]);

	if (waitpid(pid, &status, 0) != pid) {
		perror("waitpid");
		return 1;
	}

	if (!WIFEXITED(status) || WEXITSTATUS(status)) {
		printf("wrong return code\n");
		return 1;
	}

	return 0;
}

How did this ever work?

Signed-off-by: Tycho Andersen <tycho at tycho.ws>
---
 src/lxc/conf.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 9b6868940..689a2b29e 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -3737,6 +3737,9 @@ static int run_userns_fn(void *data)
 	/* Close read end of the pipe. */
 	close(d->p[0]);
 
+	if (c == '0')
+		return 1;
+
 	if (d->fn_name)
 		TRACE("calling function \"%s\"", d->fn_name);
 	/* Call function to run. */
@@ -4026,11 +4029,11 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
 	int p[2];
 	struct id_map *map;
 	struct lxc_list *cur;
-	char c = '1';
 	int ret = -1;
 	struct lxc_list *idmap = NULL, *tmplist = NULL;
 	struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
 		      *host_uid_map = NULL, *host_gid_map = NULL;
+	bool error = true;
 
 	ret = pipe(p);
 	if (ret < 0) {
@@ -4172,12 +4175,19 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
 	}
 
 	/* Tell child to proceed. */
-	if (write(p[1], &c, 1) != 1) {
+	if (write(p[1], "1", 1) != 1) {
 		SYSERROR("failed telling child process \"%d\" to proceed", pid);
 		goto on_error;
 	}
 
+	error = false;
+
 on_error:
+	/* Try to wake the child up and tell them we failed. */
+	if (error && write(p[1], "0", 1) != 1) {
+		ERROR("error telling the child about our error");
+	}
+
 	/* Wait for child to finish. */
 	if (pid > 0)
 		ret = wait_for_pid(pid);


More information about the lxc-devel mailing list