Commit 80507ee8 by Serge Hallyn

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: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent 48c63f8d
...@@ -162,8 +162,10 @@ static int signal_handler(int fd, void *data, ...@@ -162,8 +162,10 @@ static int signal_handler(int fd, void *data,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
struct signalfd_siginfo siginfo; struct signalfd_siginfo siginfo;
siginfo_t info;
int ret; int ret;
pid_t *pid = data; pid_t *pid = data;
bool init_died = false;
ret = read(fd, &siginfo, sizeof(siginfo)); ret = read(fd, &siginfo, sizeof(siginfo));
if (ret < 0) { if (ret < 0) {
...@@ -176,16 +178,23 @@ static int signal_handler(int fd, void *data, ...@@ -176,16 +178,23 @@ static int signal_handler(int fd, void *data,
return -1; 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) { if (siginfo.ssi_signo != SIGCHLD) {
kill(*pid, siginfo.ssi_signo); kill(*pid, siginfo.ssi_signo);
INFO("forwarded signal %d to pid %d", siginfo.ssi_signo, *pid); INFO("forwarded signal %d to pid %d", siginfo.ssi_signo, *pid);
return 0; return init_died ? 1 : 0;
} }
if (siginfo.ssi_code == CLD_STOPPED || if (siginfo.ssi_code == CLD_STOPPED ||
siginfo.ssi_code == CLD_CONTINUED) { siginfo.ssi_code == CLD_CONTINUED) {
INFO("container init process was stopped/continued"); INFO("container init process was stopped/continued");
return 0; return init_died ? 1 : 0;
} }
/* more robustness, protect ourself from a SIGCHLD sent /* more robustness, protect ourself from a SIGCHLD sent
...@@ -193,7 +202,7 @@ static int signal_handler(int fd, void *data, ...@@ -193,7 +202,7 @@ static int signal_handler(int fd, void *data,
*/ */
if (siginfo.ssi_pid != *pid) { if (siginfo.ssi_pid != *pid) {
WARN("invalid pid for SIGCHLD"); WARN("invalid pid for SIGCHLD");
return 0; return init_died ? 1 : 0;
} }
DEBUG("container init process exited"); DEBUG("container init process exited");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment