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:
Cédric VINCENT 2012-05-11 14:02:05 +02:00
parent 237a8b5d0b
commit 76802546a5
4 changed files with 88 additions and 3 deletions

View File

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

View File

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

View File

@ -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 */

5
tests/test-3624be91.sh Normal file
View File

@ -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 :)'