]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
su: Fix signal race during shutdown
authorTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 23 Mar 2026 18:41:12 +0000 (19:41 +0100)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 23 Mar 2026 18:41:12 +0000 (19:41 +0100)
The caught_signal variable could be modified while the original signal
handler is restored. If this happens, su does not kill itself with the
signal but just triggers another installed signal handler, ultimately
exiting with return value 1 instead.

Prevent this race by storing the value on stack and then proceed with
this definitely fixed value.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
login-utils/su-common.c

index d51fca09ebe60ec72740fc0ebde902aecb775370..acdb60a9985f029d0afd0299991da6aeee918cdb 100644 (file)
@@ -633,6 +633,8 @@ static void create_watching_parent(struct su_context *su)
        supam_cleanup(su, PAM_SUCCESS);
 
        if (caught_signal) {
+               int sig;
+
                if (su->child != (pid_t)-1) {
                        DBG(SIG, ul_debug("killing child"));
                        sleep(2);
@@ -647,7 +649,8 @@ static void create_watching_parent(struct su_context *su)
                 * terminal settings (kzak -- Jun 2013).
                 */
                DBG(SIG, ul_debug("restore signals setting"));
-               switch (caught_signal) {
+               sig = caught_signal;
+               switch (sig) {
                case SIGTERM:
                        sigaction(SIGTERM, &su->oldact[SIGTERM_IDX], NULL);
                        break;
@@ -660,11 +663,11 @@ static void create_watching_parent(struct su_context *su)
                default:
                        /* just in case that signal stuff initialization failed and
                         * caught_signal = true */
-                       caught_signal = SIGKILL;
+                       sig = SIGKILL;
                        break;
                }
-               DBG(SIG, ul_debug("self-send %d signal", caught_signal));
-               kill(getpid(), caught_signal);
+               DBG(SIG, ul_debug("self-send %d signal", sig));
+               kill(getpid(), sig);
        }
 
        DBG(MISC, ul_debug("exiting [rc=%d]", status));