From cb3a7926948c4d9668d54521cb7907436723b67a Mon Sep 17 00:00:00 2001 From: LiFeng Date: Wed, 22 Apr 2020 23:30:23 +0800 Subject: [PATCH] attach: add sigfd to monitor the exit of pid Signed-off-by: LiFeng --- src/lxc/attach.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/lxc/terminal.c | 4 +-- 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 51f5c08..b25222e 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -1197,6 +1197,56 @@ static int create_attach_timeout_thread(int64_t attach_timeout, pid_t pid) out: return ret; } + +static int attach_signal_handler(int fd, uint32_t events, void *data, + struct lxc_epoll_descr *descr) +{ + int ret; + siginfo_t info; + pid_t *pid = data; + + /* 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) { + return log_error(LXC_MAINLOOP_CLOSE, "Container attach init process %d exited", *pid); + } + + return LXC_MAINLOOP_CONTINUE; +} + +static int isulad_setup_signal_fd(sigset_t *oldmask) +{ + int ret; + sigset_t mask; + const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH}; + + /* Block everything except serious error signals. */ + ret = sigfillset(&mask); + if (ret < 0) + return -EBADF; + + for (int sig = 0; sig < (sizeof(signals) / sizeof(signals[0])); sig++) { + ret = sigdelset(&mask, signals[sig]); + if (ret < 0) + return -EBADF; + } + + ret = pthread_sigmask(SIG_BLOCK, &mask, oldmask); + if (ret < 0) + return log_error_errno(-EBADF, errno, + "Failed to set signal mask"); + + ret = signalfd(-1, &mask, SFD_CLOEXEC); + if (ret < 0) + return log_error_errno(-EBADF, + errno, "Failed to create signal file descriptor"); + + TRACE("Created signal file descriptor %d", ret); + + return ret; +} + int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process, char **err_msg) @@ -1471,6 +1521,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, int ret_parent = -1; pid_t to_cleanup_pid = pid; struct lxc_epoll_descr descr = {0}; +#ifdef HAVE_ISULAD + int isulad_sigfd; + sigset_t isulad_oldmask; + struct lxc_epoll_descr isulad_descr = {0}; +#endif /* close unneeded file descriptors */ close(ipc_sockets[1]); @@ -1541,7 +1596,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ret = lxc_attach_terminal_mainloop_init(&terminal, &descr); if (ret < 0) goto on_error; + #ifdef HAVE_ISULAD + ret = lxc_attach_terminal_mainloop_init(&terminal, &isulad_descr); + if (ret < 0) + goto on_error; + if (suffix != NULL) { (void)lxc_exec_cmd_mainloop_add(&descr, &exec_command); } @@ -1549,6 +1609,16 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, TRACE("Initialized terminal mainloop"); } +#ifdef HAVE_ISULAD + /* The signal fd has to be created before forking otherwise if the child + * process exits before we setup the signal fd, the event will be lost + * and the command will be stuck. + */ + isulad_sigfd = isulad_setup_signal_fd(&isulad_oldmask); + if (isulad_sigfd < 0) + goto close_mainloop; +#endif + /* Let the child process know to go ahead. */ status = 0; ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status)); @@ -1637,6 +1707,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, /* isulad: read error msg from pipe */ ssize_t size_read; char errbuf[BUFSIZ + 1] = {0}; + pid_t tmp_pid = *attached_process; size_read = read(conf->errpipe[0], errbuf, BUFSIZ); if (size_read > 0) { @@ -1644,6 +1715,13 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, *err_msg = safe_strdup(errbuf); goto close_mainloop; } + if (options->attach_flags & LXC_ATTACH_TERMINAL) { + ret = lxc_mainloop_add_handler(&descr, isulad_sigfd, attach_signal_handler, &tmp_pid); + if (ret < 0) { + ERROR("Failed to add signal handler for %d to mainloop", tmp_pid); + goto close_mainloop; + } + } #endif /* Now shut down communication with child, we're done. */ @@ -1672,13 +1750,19 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, } #ifdef HAVE_ISULAD + // do lxc_mainloop to make sure we do not lose any output + (void)lxc_mainloop(&isulad_descr, 100); if (g_attach_timeout_state == ATTACH_TIMEOUT && err_msg != NULL && *err_msg == NULL) { *err_msg = safe_strdup("Attach exceeded timeout"); } #endif close_mainloop: - if (options->attach_flags & LXC_ATTACH_TERMINAL) + if (options->attach_flags & LXC_ATTACH_TERMINAL) { +#ifdef HAVE_ISULAD + lxc_mainloop_close(&isulad_descr); +#endif lxc_mainloop_close(&descr); + } on_error: if (ipc_sockets[0] >= 0) { diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c index 0197503..e696b4e 100644 --- a/src/lxc/terminal.c +++ b/src/lxc/terminal.c @@ -763,11 +763,11 @@ int lxc_terminal_io_cb(int fd, uint32_t events, void *data, /* notes: do not close the master fd due to if we close the fd, the process may * recive SIGHUP and the exit code will be 141 (128 + 13) */ - return LXC_MAINLOOP_CLOSE; + return LXC_MAINLOOP_CONTINUE; } else if (fd == terminal->pipes[0][1]) { TRACE("closed stdin pipe of container stdin"); terminal->pipes[0][1] = -EBADF; - return LXC_MAINLOOP_CLOSE; + return LXC_MAINLOOP_CONTINUE; } else { ERROR("Handler received unexpected file descriptor"); } -- 1.8.3.1