mirror of https://github.com/proot-me/proot.git
Ignore terminating signals + kill all tracees on abnormal termination signals.
Terminating signals are now ignored, this permits "kill(0, ...)" without creating a dedicated process group. Note that tracees can still send SIGKILL and SIGSTOP to PRoot since these signals can't be caught. A solution would be to nullify syscalls like signal(2) when the recipient is PRoot. Regarding abnormal termination signals (segmentation fault, divide by zero, ...), they are caught to ensure no tracees will stay alive without being monitored anymore. Signals related to tty and job control are left untouched, for the sake of transparency. Change-Id: Iba60fba24b4f6f5d7c12727e2327ac713341f188 Signed-off-by: Cédric VINCENT <cedric.vincent@st.com>
This commit is contained in:
parent
237a8b5d0b
commit
76802546a5
79
src/trace.c
79
src/trace.c
|
@ -34,6 +34,7 @@
|
|||
#include <errno.h> /* errno(3), */
|
||||
#include <stdbool.h> /* bool, true, false, */
|
||||
#include <assert.h> /* assert(3), */
|
||||
#include <stdlib.h> /* atexit(3), */
|
||||
|
||||
#include "trace.h"
|
||||
#include "notice.h"
|
||||
|
@ -174,15 +175,91 @@ bool attach_process(pid_t pid)
|
|||
return (tracee != NULL);
|
||||
}
|
||||
|
||||
/* Send the KILL signal to all [known] tracees. */
|
||||
static void kill_all_tracees()
|
||||
{
|
||||
int kill_tracee(pid_t pid)
|
||||
{
|
||||
kill(pid, SIGKILL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach_tracee(kill_tracee);
|
||||
}
|
||||
|
||||
static void kill_all_tracees2(int signum, siginfo_t *siginfo, void *ucontext)
|
||||
{
|
||||
notice(WARNING, INTERNAL, "signal %d received from process %d", signum, siginfo->si_pid);
|
||||
kill_all_tracees();
|
||||
|
||||
/* Exit immediately for system signals (segmentation fault,
|
||||
* illegal instruction, ...), otherwise exit cleanly through
|
||||
* the event loop. */
|
||||
if (signum != SIGQUIT)
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int event_loop()
|
||||
{
|
||||
struct sigaction signal_action;
|
||||
struct tracee_info *tracee;
|
||||
int last_exit_status = -1;
|
||||
int tracee_status;
|
||||
long status;
|
||||
int signum;
|
||||
int signal;
|
||||
pid_t pid;
|
||||
|
||||
/* Kill all tracees when exiting. */
|
||||
status = atexit(kill_all_tracees);
|
||||
if (status != 0)
|
||||
notice(WARNING, INTERNAL, "atexit() failed");
|
||||
|
||||
/* All signals are blocked when the signal handler is called.
|
||||
* SIGINFO is used to know which process has signaled us and
|
||||
* RESTART is used to restart waitpid(2) seamlessly. */
|
||||
bzero(&signal_action, sizeof(signal_action));
|
||||
signal_action.sa_flags = SA_SIGINFO | SA_RESTART;
|
||||
status = sigfillset(&signal_action.sa_mask);
|
||||
if (status < 0)
|
||||
notice(WARNING, SYSTEM, "sigfillset()");
|
||||
|
||||
/* Handle all signals. */
|
||||
for (signum = 0; signum < SIGRTMAX; signum++) {
|
||||
switch (signum) {
|
||||
case SIGQUIT:
|
||||
case SIGILL:
|
||||
case SIGABRT:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
/* Kill all tracees on abnormal termination
|
||||
* signals. This ensures no process is left
|
||||
* untraced. */
|
||||
signal_action.sa_sigaction = kill_all_tracees2;
|
||||
break;
|
||||
|
||||
case SIGCHLD:
|
||||
case SIGCONT:
|
||||
case SIGSTOP:
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
/* The default action is OK for these signals,
|
||||
* they are related to tty and job control. */
|
||||
continue;
|
||||
|
||||
default:
|
||||
/* Ignore all other signals, including
|
||||
* terminating ones (^C for instance). */
|
||||
signal_action.sa_sigaction = (void *)SIG_IGN;
|
||||
break;
|
||||
}
|
||||
|
||||
status = sigaction(signum, &signal_action, NULL);
|
||||
if (status < 0 && errno != EINVAL)
|
||||
notice(WARNING, SYSTEM, "sigaction(%d)", signum);
|
||||
}
|
||||
|
||||
signal = 0;
|
||||
while (1) {
|
||||
/* Wait for the next tracee's stop. */
|
||||
|
@ -199,7 +276,7 @@ int event_loop()
|
|||
foreach_tracee(check_fd);
|
||||
|
||||
/* Get the information about this tracee. */
|
||||
tracee = get_tracee_info(pid);
|
||||
tracee = get_tracee_info(pid, true);
|
||||
assert(tracee != NULL);
|
||||
|
||||
if (WIFEXITED(tracee_status)) {
|
||||
|
|
|
@ -140,7 +140,7 @@ size_t get_nb_tracees()
|
|||
* Search in the table tracee_infos[] for the entry related to the
|
||||
* tracee @pid.
|
||||
*/
|
||||
struct tracee_info *get_tracee_info(pid_t pid)
|
||||
struct tracee_info *get_tracee_info(pid_t pid, bool create)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
|
@ -149,6 +149,9 @@ struct tracee_info *get_tracee_info(pid_t pid)
|
|||
if (tracee_infos[i].pid == pid)
|
||||
return &tracee_infos[i];
|
||||
|
||||
if (!create)
|
||||
return NULL;
|
||||
|
||||
/* Create the tracee_infos[] entry dynamically. */
|
||||
return new_tracee(pid);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ extern void init_module_tracee_info(void);
|
|||
extern struct tracee_info *new_tracee(pid_t pid);
|
||||
extern void delete_tracee(struct tracee_info *tracee);
|
||||
extern size_t get_nb_tracees(void);
|
||||
extern struct tracee_info *get_tracee_info(pid_t pid);
|
||||
extern struct tracee_info *get_tracee_info(pid_t pid, bool create);
|
||||
extern int foreach_tracee(foreach_tracee_t callback);
|
||||
|
||||
#endif /* TRACEE_INFO_H */
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
if [ -z `which sh` ] || [ -z `which kill` ] || [ -z `which grep` ] || [ -z `which cut` ]; then
|
||||
exit 125;
|
||||
fi
|
||||
|
||||
${PROOT} / sh -c 'kill -15 $(grep TracerPid /proc/self/status | cut -f 2 -d :)'
|
Loading…
Reference in New Issue