From: Tobias Stoeckmann Date: Fri, 9 Jan 2026 16:23:38 +0000 (+0100) Subject: su: Kill child outside of signal handler X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b42b1cc9b9722295ad23310378d535fea42a31da;p=thirdparty%2Fshadow.git su: Kill child outside of signal handler 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 Reviewed-by: Ruihan Li Signed-off-by: Tobias Stoeckmann --- diff --git a/src/su.c b/src/su.c index 8c355d07f..9f32733ee 100644 --- 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;