[lxc-devel] [PATCH] start.c: handle potential signal flood

Serge Hallyn serge.hallyn at ubuntu.com
Thu Aug 29 15:44:41 UTC 2013


Signalfd does not guarantee that we'll get an event for every signal.
So if 3 tasks exit at the same time, we may get only one sigchld
event.  Therefore, in signal_handler(), always check whether init has
exited.  Do with with WNOWAIT so that we can still wait4 to cleanup
the init after lxc_poll() exists (rather than complicating the code).

Note - there is still a race in the kernel which can cause the
container init to become a defunct child of the host init (!).  This
doesn't solve that, but is a potential (if very unlikely) race which
apw pointed out while we were trying to create a reproducer for the
kernel bug.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/start.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/lxc/start.c b/src/lxc/start.c
index f552e35..a574a8d 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -162,8 +162,10 @@ static int signal_handler(int fd, void *data,
 			   struct lxc_epoll_descr *descr)
 {
 	struct signalfd_siginfo siginfo;
+	siginfo_t info;
 	int ret;
 	pid_t *pid = data;
+	bool init_died = false;
 
 	ret = read(fd, &siginfo, sizeof(siginfo));
 	if (ret < 0) {
@@ -176,16 +178,23 @@ static int signal_handler(int fd, void *data,
 		return -1;
 	}
 
+	// check whether init is running
+	info.si_pid = 0;
+	ret = waitid(P_PID, *pid, &info, WEXITED | WNOWAIT | WNOHANG);
+	if (ret == 0 && info.si_pid == *pid) {
+		init_died = true;
+	}
+
 	if (siginfo.ssi_signo != SIGCHLD) {
 		kill(*pid, siginfo.ssi_signo);
 		INFO("forwarded signal %d to pid %d", siginfo.ssi_signo, *pid);
-		return 0;
+		return init_died ? 1 : 0;
 	}
 
 	if (siginfo.ssi_code == CLD_STOPPED ||
 	    siginfo.ssi_code == CLD_CONTINUED) {
 		INFO("container init process was stopped/continued");
-		return 0;
+		return init_died ? 1 : 0;
 	}
 
 	/* more robustness, protect ourself from a SIGCHLD sent
@@ -193,7 +202,7 @@ static int signal_handler(int fd, void *data,
 	 */
 	if (siginfo.ssi_pid != *pid) {
 		WARN("invalid pid for SIGCHLD");
-		return 0;
+		return init_died ? 1 : 0;
 	}
 
 	DEBUG("container init process exited");
-- 
1.8.3.2





More information about the lxc-devel mailing list