From: Serge Hallyn Date: Thu, 29 Aug 2013 15:41:19 +0000 (-0500) Subject: start.c: handle potential signal flood X-Git-Tag: lxc-1.0.0.alpha1~1^2~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80507ee8eb66f4f23494caae26f6d2f0b50480b6;p=thirdparty%2Flxc.git start.c: handle potential signal flood 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 Acked-by: Stéphane Graber --- diff --git a/src/lxc/start.c b/src/lxc/start.c index f552e35dc..a574a8d78 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");