]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
su: Kill child outside of signal handler
authorTobias Stoeckmann <tobias@stoeckmann.org>
Fri, 9 Jan 2026 16:23:38 +0000 (17:23 +0100)
committerAlejandro Colomar <foss+github@alejandro-colomar.es>
Sun, 11 Jan 2026 14:46:59 +0000 (15:46 +0100)
This simplifies the alarm handler to just set a volatile
sig_atomic_t like catch_signals does, which makes the handler way
easier to review.

Reviewed-by: Alejandro Colomar <alx@kernel.org>
Reviewed-by: Ruihan Li <lrh2000@pku.edu.cn>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
src/su.c

index 8c355d07f637474d838723cd3be4984d242ace60..9f32733ee2d0b3888a79d60be56f8c9b83952e32 100644 (file)
--- a/src/su.c
+++ b/src/su.c
@@ -98,6 +98,7 @@ static char kill_msg[256];
 static char wait_msg[256];
 static pam_handle_t *pamh = NULL;
 static volatile sig_atomic_t caught = 0;
+static volatile sig_atomic_t timeout = 0;
 /* PID of the child, in case it needs to be killed */
 static pid_t pid_child = 0;
 #endif
@@ -117,6 +118,7 @@ static void execve_shell (const char *shellname,
 #ifdef USE_PAM
 static void kill_child(int);
 static void prepare_pam_close_session (void);
+static void set_timeout(int);
 #else                          /* !USE_PAM */
 static void die (int);
 static bool iswheel (const char *);
@@ -180,6 +182,12 @@ kill_child(int)
        }
        _exit (255);
 }
+
+static void
+set_timeout(int)
+{
+       timeout = 1;
+}
 #endif                         /* USE_PAM */
 
 /* borrowed from GNU sh-utils' "su.c" */
@@ -409,7 +417,7 @@ static void prepare_pam_close_session (void)
 
                /* Send SIGKILL to the child if it doesn't
                 * exit within 2 seconds (after SIGTERM) */
-               (void) signal (SIGALRM, kill_child);
+               (void) signal (SIGALRM, set_timeout);
                (void) signal (SIGCHLD, catch_signals);
                (void) alarm (2);
 
@@ -418,6 +426,10 @@ static void prepare_pam_close_session (void)
 
                while (0 == waitpid (pid_child, &status, WNOHANG)) {
                        sigsuspend (&ourset);
+                       if (timeout) {
+                               kill_child(0);
+                               /* Never reached (_exit called). */
+                       }
                }
                pid_child = 0;