From 07138e1e1d3b728efdd6e8789f60c4a277a25ff7 Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Fri, 28 Aug 2020 13:48:20 +0100 Subject: [PATCH] ecore exe - fig signal block to unblock again - some sys dont on exec it seems some libc's or systes dont reset signal mask blocks on exec(). this unblocks manuaklly jus befor eexec, moves blocking to before fork and adds a "nuke all signal handlers" in the child process. fixes T8797 --- src/lib/ecore/ecore_exe_posix.c | 88 ++++++++++++++++++--------------- src/lib/ecore/efl_exe.c | 77 ++++++++++++++++------------- 2 files changed, 92 insertions(+), 73 deletions(-) diff --git a/src/lib/ecore/ecore_exe_posix.c b/src/lib/ecore/ecore_exe_posix.c index 85b7adee45..635fc0678b 100644 --- a/src/lib/ecore/ecore_exe_posix.c +++ b/src/lib/ecore/ecore_exe_posix.c @@ -289,56 +289,64 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe) pid_t pid = 0; volatile int vfork_exec_errno = 0; + sigset_t newset, oldset; + + sigemptyset(&newset); + sigaddset(&newset, SIGPIPE); + sigaddset(&newset, SIGALRM); + sigaddset(&newset, SIGCHLD); + sigaddset(&newset, SIGUSR1); + sigaddset(&newset, SIGUSR2); + sigaddset(&newset, SIGHUP); + sigaddset(&newset, SIGQUIT); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGTERM); + sigaddset(&newset, SIGBUS); + sigaddset(&newset, SIGCONT); + sigaddset(&newset, SIGWINCH); +#ifdef SIGEMT + sigaddset(&newset, SIGEMT); +#endif +#ifdef SIGIO + sigaddset(&newset, SIGIO); +#endif +#ifdef SIGTSTP + sigaddset(&newset, SIGTSTP); +#endif +#ifdef SIGTTIN + sigaddset(&newset, SIGTTIN); +#endif +#ifdef SIGTTOU + sigaddset(&newset, SIGTTOU); +#endif +#ifdef SIGVTALRM + sigaddset(&newset, SIGVTALRM); +#endif +#ifdef SIGPWR + sigaddset(&newset, SIGPWR); +#endif + // block all those nasty signals we don't want messing with things + // in signal handlers while we go from fork to exec in the child + pthread_sigmask(SIG_BLOCK, &newset, &oldset); /* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */ /* signal(SIGPIPE, SIG_IGN); We only want EPIPE on errors */ pid = fork(); if (pid == -1) { + pthread_sigmask(SIG_SETMASK, &oldset, NULL); ERR("Failed to fork process"); pid = 0; } else if (pid == 0) /* child */ { - sigset_t newset; + struct sigaction sa; + int sig; - sigemptyset(&newset); - sigaddset(&newset, SIGPIPE); - sigaddset(&newset, SIGALRM); - sigaddset(&newset, SIGCHLD); - sigaddset(&newset, SIGUSR1); - sigaddset(&newset, SIGUSR2); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGTERM); - sigaddset(&newset, SIGBUS); - sigaddset(&newset, SIGCONT); - sigaddset(&newset, SIGWINCH); -#ifdef SIGEMT - sigaddset(&newset, SIGEMT); -#endif -#ifdef SIGIO - sigaddset(&newset, SIGIO); -#endif -#ifdef SIGTSTP - sigaddset(&newset, SIGTSTP); -#endif -#ifdef SIGTTIN - sigaddset(&newset, SIGTTIN); -#endif -#ifdef SIGTTOU - sigaddset(&newset, SIGTTOU); -#endif -#ifdef SIGVTALRM - sigaddset(&newset, SIGVTALRM); -#endif -#ifdef SIGPWR - sigaddset(&newset, SIGPWR); -#endif - // block all those nasty signals we don't want messing with things - // in signal handlers while we go from fork to exec in the child - pthread_sigmask(SIG_BLOCK, &newset, NULL); + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + for (sig = 0; sig < 32; sig++) sigaction(sig, &sa, NULL); #ifdef HAVE_SYSTEMD char **env = NULL, **e; @@ -439,13 +447,15 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe) except[0] = statusPipe[1]; eina_file_close_from(3, except); /* Run the actual command. */ - _ecore_exe_exec_it(exe_cmd, flags); /* no return */ + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + _ecore_exe_exec_it(exe_cmd, flags); /* no return */ } } _exit(-1); } else /* parent */ { + pthread_sigmask(SIG_SETMASK, &oldset, NULL); /* Close the unused pipes. */ E_NO_ERRNO(result, close(statusPipe[1]), ok); diff --git a/src/lib/ecore/efl_exe.c b/src/lib/ecore/efl_exe.c index 445a3dfab2..03c52ab845 100644 --- a/src/lib/ecore/efl_exe.c +++ b/src/lib/ecore/efl_exe.c @@ -435,39 +435,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd) if (loop) tdl = efl_data_scope_get(loop, EFL_TASK_CLASS); if (pd->env) itr = efl_core_env_content_get(pd->env); if (pd->env) itr2 = efl_core_env_content_get(pd->env); - pd->pid = fork(); - - if (pd->pid != 0) - { - if (itr) eina_iterator_free(itr); - if (itr2) eina_iterator_free(itr2); - // parent process is here inside this if block - if (td->flags & EFL_TASK_FLAGS_USE_STDIN) close(pipe_stdin[0]); - if (td->flags & EFL_TASK_FLAGS_USE_STDOUT) close(pipe_stdout[1]); - // fork failed... close up and clean and release locks - if (pd->pid == -1) - { - _close_fds(pd); - _ecore_signal_pid_unlock(); - return EINA_FALSE; - } - // register this pid in the core sigchild/pid exit code watcher - _ecore_signal_pid_register(pd->pid, pd->fd.exited_write); - pd->exit_handler = - efl_add(EFL_LOOP_HANDLER_CLASS, obj, - efl_loop_handler_fd_set(efl_added, pd->fd.exited_read), - efl_event_callback_add(efl_added, - EFL_LOOP_HANDLER_EVENT_READ, - _cb_exe_exit_read, obj), - efl_loop_handler_active_set(efl_added, - EFL_LOOP_HANDLER_FLAGS_READ)); - _ecore_signal_pid_unlock(); - pd->run = EINA_TRUE; - return EINA_TRUE; - } - // this code is in the child here, and is temporary setup until we - // exec() the child to replace everything. - sigset_t newset; + sigset_t newset, oldset; sigemptyset(&newset); sigaddset(&newset, SIGPIPE); @@ -505,7 +473,47 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd) # endif // block all those nasty signals we don't want messing with things // in signal handlers while we go from fork to exec in the child - pthread_sigmask(SIG_BLOCK, &newset, NULL); + pthread_sigmask(SIG_BLOCK, &newset, &oldset); + pd->pid = fork(); + + if (pd->pid != 0) + { + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + if (itr) eina_iterator_free(itr); + if (itr2) eina_iterator_free(itr2); + // parent process is here inside this if block + if (td->flags & EFL_TASK_FLAGS_USE_STDIN) close(pipe_stdin[0]); + if (td->flags & EFL_TASK_FLAGS_USE_STDOUT) close(pipe_stdout[1]); + // fork failed... close up and clean and release locks + if (pd->pid == -1) + { + _close_fds(pd); + _ecore_signal_pid_unlock(); + return EINA_FALSE; + } + // register this pid in the core sigchild/pid exit code watcher + _ecore_signal_pid_register(pd->pid, pd->fd.exited_write); + pd->exit_handler = + efl_add(EFL_LOOP_HANDLER_CLASS, obj, + efl_loop_handler_fd_set(efl_added, pd->fd.exited_read), + efl_event_callback_add(efl_added, + EFL_LOOP_HANDLER_EVENT_READ, + _cb_exe_exit_read, obj), + efl_loop_handler_active_set(efl_added, + EFL_LOOP_HANDLER_FLAGS_READ)); + _ecore_signal_pid_unlock(); + pd->run = EINA_TRUE; + return EINA_TRUE; + } + struct sigaction sa; + int sig; + + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + for (sig = 0; sig < 32; sig++) sigaction(sig, &sa, NULL); + // this code is in the child here, and is temporary setup until we + // exec() the child to replace everything. if (td->flags & EFL_TASK_FLAGS_USE_STDIN) close(pipe_stdin[1]); if (td->flags & EFL_TASK_FLAGS_USE_STDOUT) close(pipe_stdout[0]); @@ -633,6 +641,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd) procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sig); } # endif + pthread_sigmask(SIG_SETMASK, &oldset, NULL); // actually execute! _exec(cmd, pd->flags, td->flags); // we couldn't exec... uh oh. HAAAAAAAALP!