[sudo-users] Sudo ignoring SIGTERM unless connected to strace

Todd C. Miller Todd.Miller at millert.dev
Sat Nov 5 19:33:49 MDT 2022


I think you'll find that the behavior is different depending on
whether sudo is run from the shell or as part of a script.

When not running a command in a pseudo-terminal, sudo ignores signals
send by a process in the command's process group, expecting that
the command will already have received the signal (this prevents
the command from getting a signal multiple times).  When the command
exits, sudo will too.

For example:

millert at linux-build:~$ sudo sleep infinity &
[1] 5424
millert at linux-build:~$ kill 5424
[1]+  Terminated              sudo sleep 100

However, when sudo is run from a shell script this assumption is
not valid.  In this case, both sudo and the command are (usually)
running in the same process group as the shell script.

The behavior you are seeing is a bug and sudo should forward the
signal to the command when it is not the process group leader.

I'm testing the following fix now.

 - todd

diff -r 6268fbabdb16 src/exec_nopty.c
--- a/src/exec_nopty.c	Fri Nov 04 14:19:27 2022 -0600
+++ b/src/exec_nopty.c	Sat Nov 05 19:31:41 2022 -0600
@@ -122,6 +122,7 @@ signal_cb_nopty(int signo, int what, voi
     struct sudo_ev_siginfo_container *sc = v;
     struct exec_closure *ec = sc->closure;
     char signame[SIG2STR_MAX];
+    pid_t si_pgrp;
     debug_decl(signal_cb_nopty, SUDO_DEBUG_EXEC);
 
     if (ec->cmnd_pid == -1)
@@ -151,38 +152,44 @@ signal_cb_nopty(int signo, int what, voi
     case SIGQUIT:
     case SIGTSTP:
 	/*
-	 * Only forward user-generated signals not sent by a process in
-	 * the command's own process group.  Signals sent by the kernel
-	 * may include SIGTSTP when the user presses ^Z.  Curses programs
-	 * often trap ^Z and send SIGTSTP to their own pgrp, so we don't
-	 * want to send an extra SIGTSTP.
+	 * Only forward user-generated signals not sent by a process other than
+	 * the command itself or a member of the command's process group (but
+	 * only when either sudo or the command is the process group leader).
+	 * Signals sent by the kernel may include SIGTSTP when the user presses
+	 * ^Z.  Curses programs often trap ^Z and send SIGTSTP to their own
+	 * process group, so we don't want to send an extra SIGTSTP.
 	 */
 	if (!USER_SIGNALED(sc->siginfo))
 	    debug_return;
 	if (sc->siginfo->si_pid != 0) {
-	    pid_t si_pgrp = getpgid(sc->siginfo->si_pid);
+	    if (sc->siginfo->si_pid == ec->cmnd_pid)
+		debug_return;
+	    si_pgrp = getpgid(sc->siginfo->si_pid);
 	    if (si_pgrp != -1) {
-		if (si_pgrp == ec->ppgrp || si_pgrp == ec->cmnd_pid)
+		if (si_pgrp == ec->cmnd_pid)
 		    debug_return;
-	    } else if (sc->siginfo->si_pid == ec->cmnd_pid) {
-		debug_return;
+		if (si_pgrp == ec->ppgrp && ec->ppgrp == ec->sudo_pid)
+		    debug_return;
 	    }
 	}
 	break;
     default:
 	/*
-	 * Do not forward signals sent by a process in the command's process
-	 * group, as we don't want the command to indirectly kill itself.
-	 * For example, this can happen with some versions of reboot that
-	 * call kill(-1, SIGTERM) to kill all other processes.
+	 * Do not forward signals sent by the command itself or a member of the
+	 * command's process group (but only when either sudo or the command is
+	 * the process group leader).  We don't want the command to indirectly
+	 * kill itself.  For example, this can happen with some versions of
+	 * reboot that call kill(-1, SIGTERM) to kill all other processes.
 	 */
 	if (USER_SIGNALED(sc->siginfo) && sc->siginfo->si_pid != 0) {
-	    pid_t si_pgrp = getpgid(sc->siginfo->si_pid);
+	    if (sc->siginfo->si_pid == ec->cmnd_pid)
+		debug_return;
+	    si_pgrp = getpgid(sc->siginfo->si_pid);
 	    if (si_pgrp != -1) {
-		if (si_pgrp == ec->ppgrp || si_pgrp == ec->cmnd_pid)
+		if (si_pgrp == ec->cmnd_pid)
 		    debug_return;
-	    } else if (sc->siginfo->si_pid == ec->cmnd_pid) {
-		debug_return;
+		if (si_pgrp == ec->ppgrp && ec->ppgrp == ec->sudo_pid)
+		    debug_return;
 	    }
 	}
 	break;
@@ -210,6 +217,7 @@ fill_exec_closure(struct exec_closure *e
     debug_decl(fill_exec_closure, SUDO_DEBUG_EXEC);
 
     /* Fill in the non-event part of the closure. */
+    ec->sudo_pid = getpid();
     ec->ppgrp = getpgrp();
     ec->cstat = cstat;
     ec->details = details;
diff -r 6268fbabdb16 src/sudo_exec.h
--- a/src/sudo_exec.h	Fri Nov 04 14:19:27 2022 -0600
+++ b/src/sudo_exec.h	Sat Nov 05 19:31:41 2022 -0600
@@ -74,6 +74,7 @@ struct exec_closure {
     struct sudo_event *sigwinch_event;
     struct command_status *cstat;
     void *intercept;
+    pid_t sudo_pid;
     pid_t monitor_pid;
     pid_t cmnd_pid;
     pid_t ppgrp;


More information about the sudo-users mailing list