From: Benjamin Berg <benja...@sipsolutions.net> When in seccomp mode, we would hang forever on the futex if a child has died unexpectedly. In contrast, ptrace mode will notice it and kill the corresponding thread when it fails to run it.
Fix this issue by simply printing a message and aborting. In this case something from the outside (e.g. OOM killer) has interferred with the machine and it is reasonable to not try to recover. Signed-off-by: Benjamin Berg <benja...@sipsolutions.net> --- arch/um/include/shared/os.h | 1 + arch/um/os-Linux/process.c | 40 +++++++++++++++++++++++++++++++++++++ arch/um/os-Linux/signal.c | 7 +++++++ 3 files changed, 48 insertions(+) diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index d1f1dedad83b..07683f45d7e1 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -192,6 +192,7 @@ extern void get_host_cpu_features( extern int create_mem_file(unsigned long long len); /* process.c */ +void os_check_child_lost(void); extern unsigned long os_process_pc(int pid); extern int os_process_parent(int pid); extern void os_alarm_process(int pid); diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index e52dd37ddadc..db98fc79d9e2 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -17,6 +17,7 @@ #include <init.h> #include <longjmp.h> #include <os.h> +#include <skas/skas.h> #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -102,9 +103,18 @@ void os_stop_process(int pid) void os_kill_process(int pid, int reap_child) { + sigset_t chld; + + /* Block SIGCHLD so that we can reap it before the handler runs. */ + sigemptyset(&chld); + sigaddset(&chld, SIGCHLD); + sigprocmask(SIG_BLOCK, &chld, NULL); + kill(pid, SIGKILL); if (reap_child) CATCH_EINTR(waitpid(pid, NULL, __WALL)); + + sigprocmask(SIG_UNBLOCK, &chld, NULL); } /* Kill off a ptraced child by all means available. kill it normally first, @@ -114,11 +124,39 @@ void os_kill_process(int pid, int reap_child) void os_kill_ptraced_process(int pid, int reap_child) { + sigset_t chld; + + /* Block SIGCHLD so that we can reap it before the handler runs. */ + sigemptyset(&chld); + sigaddset(&chld, SIGCHLD); + sigprocmask(SIG_BLOCK, &chld, NULL); + kill(pid, SIGKILL); ptrace(PTRACE_KILL, pid); ptrace(PTRACE_CONT, pid); if (reap_child) CATCH_EINTR(waitpid(pid, NULL, __WALL)); + + sigprocmask(SIG_UNBLOCK, &chld, NULL); +} + +void os_check_child_lost(void) +{ + int status; + pid_t pid; + + /* + * Check if we can reap a child. + * Any expected kills will clean up without this handler being fired. + */ + pid = waitpid(-1, &status, WNOHANG); + if (pid <= 0) + return; + + os_warn("Child %d died unexpectedly with status %d, cannot recover in seccomp mode!\r\n", + pid, status); + /* Kill ourselves including all children. */ + killpg(os_getpid(), SIGABRT); } /* Don't use the glibc version, which caches the result in TLS. It misses some @@ -283,5 +321,7 @@ void init_new_thread_signals(void) set_handler(SIGBUS); signal(SIGHUP, SIG_IGN); set_handler(SIGIO); + if (using_seccomp) + set_handler(SIGCHLD); signal(SIGWINCH, SIG_IGN); } diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 24a403a70a02..d8c92e04c873 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -108,6 +108,11 @@ static void timer_real_alarm_handler(mcontext_t *mc) timer_handler(SIGALRM, NULL, ®s); } +static void sig_child_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) +{ + os_check_child_lost(); +} + void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) { int enabled; @@ -169,6 +174,8 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { [SIGIO] = sig_handler, [SIGWINCH] = sig_handler, + /* SIGCHLD is only registered in seccomp mode. */ + [SIGCHLD] = sig_child_handler, [SIGALRM] = timer_alarm_handler, [SIGUSR1] = sigusr1_handler, -- 2.38.1 _______________________________________________ linux-um mailing list linux-um@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-um