From: Todd C. Miller Date: Wed, 14 Oct 2009 13:01:04 +0000 (+0000) Subject: Associate the grandchild's pgrp with the tty instead of the child's X-Git-Tag: SUDO_1_7_3~237 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0d04ffc40c5550ca04b9df5fde8e0aad3ab556c9;p=sudo Associate the grandchild's pgrp with the tty instead of the child's and just get suspend notifications via SIGCHLD instead of directly. This fixes a hang with programs that try to set terminal attributes and is more consistent with how the shell handles things. --- diff --git a/script.c b/script.c index 6c4ca0888..9d5a3246b 100644 --- a/script.c +++ b/script.c @@ -102,8 +102,6 @@ static void sync_winsize __P((int src, int dst)); static void handler __P((int s)); static void sigchild __P((int s)); static void sigwinch __P((int s)); -static void sigtstp __P((int s)); -static void sigrepost __P((int s)); static int get_pty __P((int *master, int *slave)); static void flush_output __P((struct script_buf *output, struct timeval *then, struct timeval *now, FILE *ofile, FILE *tfile)); @@ -504,24 +502,10 @@ script_child(path, argv) } #endif - /* Setup signal handlers for child exit, and tty-related signals. */ + /* Setup signal handler for child stop/exit */ zero_bytes(&sa, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - - /* These tty-related signals get relayed back to the parent. */ - sa.sa_handler = sigtstp; - sigaction(SIGTSTP, &sa, NULL); - sigaction(SIGTTIN, &sa, NULL); - sigaction(SIGTTOU, &sa, NULL); - - /* These signals just get posted to the grandchilds pgrp. */ - sa.sa_handler = sigrepost; - sigaction(SIGQUIT, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - - /* Do not want child stop notifications. */ - sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; sa.sa_handler = sigchild; sigaction(SIGCHLD, &sa, NULL); @@ -729,12 +713,16 @@ script_grandchild(path, argv, rbac_enabled) char *argv[]; int rbac_enabled; { - /* Also set process group here to avoid a race condition. */ - setpgid(0, getpid()); + pid_t self = getpid(); + + /* Also set our process group here to avoid a race condition. */ + setpgid(0, self); dup2(script_fds[SFD_SLAVE], STDIN_FILENO); dup2(script_fds[SFD_SLAVE], STDOUT_FILENO); dup2(script_fds[SFD_SLAVE], STDERR_FILENO); + if (tcsetpgrp(STDIN_FILENO, self) != 0) + warning("tcsetpgrp"); /* * Close old fds and exec command. @@ -744,6 +732,7 @@ script_grandchild(path, argv, rbac_enabled) close(script_fds[SFD_LOG]); close(script_fds[SFD_OUTPUT]); close(script_fds[SFD_TIMING]); + #ifdef HAVE_SELINUX if (rbac_enabled) selinux_execv(path, argv); @@ -794,17 +783,22 @@ sigchild(signo) #ifdef sudo_waitpid do { pid = sudo_waitpid(grandchild, &grandchild_status, WNOHANG); - if (pid == grandchild) { - alive = 0; + if (pid == grandchild) break; - } } while (pid > 0 || (pid == -1 && errno == EINTR)); #else do { pid = wait(&grandchild_status); } while (pid == -1 && errno == EINTR); - alive = 0; #endif + if (pid == grandchild) { + if (WIFSTOPPED(grandchild_status)) { + suspended = 1; + signo = WSTOPSIG(grandchild_status); + } else { + alive = 0; + } + } errno = serrno; } @@ -827,6 +821,8 @@ sigtstp(s) { int serrno = errno; + write(STDERR_FILENO, "sigtstp\n", 8); + /* Event loop needs to know which signal to relay to parent. */ signo = s;