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
This commit is contained in:
Carsten Haitzler 2020-08-28 13:48:20 +01:00
parent b954640db8
commit 07138e1e1d
2 changed files with 92 additions and 73 deletions

View File

@ -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);

View File

@ -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!