From: Todd C. Miller Date: Tue, 5 Oct 2004 19:13:56 +0000 (+0000) Subject: Detach from tracee on SIGHUP, SIGINT and SIGTERM. Now "sudo reboot" X-Git-Tag: SUDO_1_7_0~893 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=385dfb26962882504d881100a0b123e5071ea336;p=sudo Detach from tracee on SIGHUP, SIGINT and SIGTERM. Now "sudo reboot" doesn't cause reboot to inadvertanly kill itself. --- diff --git a/mon_systrace.c b/mon_systrace.c index 27c265c3e..55ea73e83 100644 --- a/mon_systrace.c +++ b/mon_systrace.c @@ -86,18 +86,16 @@ bad: } static void -sigusr1(signo) +catchsig(signo) int signo; { + dodetach = signo; return; } /* - * Fork a process that traces the command to be run and its descendents. - * - * TODO: - * should the tracing process catch signals and detach? - * (right now "sudo reboot" fails due to tracing) + * Fork a process that monitors the command to be run and its descendents. + * The monitoring process will detach upon receipt of SIGHUP, SIGINT or SIGTERM. */ void systrace_attach(pid) @@ -124,7 +122,7 @@ systrace_attach(pid) err(1, "sigprocmask"); sigemptyset(&sa.sa_mask); sa.sa_flags = 0; - sa.sa_handler = sigusr1; + sa.sa_handler = catchsig; if (sigaction(SIGUSR1, &sa, &osa) != 0) err(1, "sigaction"); @@ -146,14 +144,22 @@ systrace_attach(pid) return; } - /* reset signal state for tracer */ + /* set signal state for tracer */ + dodetach = 0; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = catchsig; if (sigaction(SIGUSR1, &osa, NULL) != 0 || + sigaction(SIGHUP, &sa, NULL) != 0 || + sigaction(SIGINT, &sa, NULL) != 0 || + sigaction(SIGTERM, &sa, NULL) != 0 || sigprocmask(SIG_SETMASK, &oset, NULL) != 0) { warn("unable to setup signals for %s", user_cmnd); goto fail; } /* become a daemon */ + set_perms(PERM_FULL_ROOT); if (setsid() == -1) { warn("setsid"); kill(pid, SIGKILL); @@ -190,9 +196,13 @@ systrace_attach(pid) for (;;) { nread = read(fd, &msg, sizeof(msg)); if (nread != sizeof(msg)) { + if (dodetach) { + detachall(fd); + _exit(0); + } if (nread == -1 && (errno == EINTR || errno == EAGAIN)) continue; - killall(&children, SIGKILL); + killall(SIGKILL); _exit(nread != 0); /* shouldn't happen */ } @@ -275,7 +285,7 @@ systrace_attach(pid) } fail: - killall(&children, SIGKILL); + killall(SIGKILL); _exit(1); } @@ -903,12 +913,24 @@ check_execve(fd, pid, seqnr, askp, cookie, policyp, errorp) * Kill all pids in the list */ static void -killall(head, sig) - struct listhead *head; +killall(sig) int sig; { struct childinfo *child; - for (child = head->first; child != NULL; child = child->next) + for (child = children.first; child != NULL; child = child->next) (void) kill(child->pid, sig); } + +/* + * Detach all traced processes. + */ +static void +detachall(fd) + int fd; +{ + struct childinfo *child; + + for (child = children.first; child != NULL; child = child->next) + (void) ioctl(fd, STRIOCDETACH, &child->pid); +} diff --git a/mon_systrace.h b/mon_systrace.h index f1063aa0b..24206ecf6 100644 --- a/mon_systrace.h +++ b/mon_systrace.h @@ -41,7 +41,9 @@ static int update_env __P((int, pid_t, u_int16_t, struct str_msg_ask *)); static schandler_t find_handler __P((pid_t, int)); static ssize_t read_string __P((int, pid_t, void *, char *, size_t)); static struct childinfo *find_child __P((pid_t)); -static void killall __P((struct listhead *, int)); +static void catchsig __P((int)); +static void detachall __P((int)); +static void killall __P((int)); static void new_child __P((pid_t, pid_t)); static void rm_child __P((pid_t)); static void update_child __P((pid_t, uid_t)); @@ -49,6 +51,7 @@ static void update_child __P((pid_t, uid_t)); static struct listhead children; /* list of children being traced */ static int initialized; /* set to true when we are inited */ +static volatile sig_atomic_t dodetach; /* caught signal */ struct listhead { void *first;