]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
pty-session: handle SIGALRM instead of aborting
authorlzwind <liuzheng@uniontech.com>
Fri, 24 Jul 2026 13:00:15 +0000 (21:00 +0800)
committerlzwind <liuzheng@uniontech.com>
Fri, 24 Jul 2026 13:00:15 +0000 (21:00 +0800)
ul_pty_signals_setup() subscribes to SIGALRM through the signalfd set,
but handle_signal() has no case for it, so a SIGALRM delivered to the
proxy (e.g. an alarm(2) timer armed before execve(), or an external
"kill -ALRM") falls through to "default: abort()".

The abort() terminates script/su --pty/runuser --pty with SIGABRT before
ul_pty_cleanup() runs, leaving the user's terminal in raw mode (no echo,
no canonical mode, no signal generation) until "stty sane" is run.

Treat SIGALRM like the other terminating signals (SIGHUP/SIGTERM/SIGINT/
SIGQUIT): record it in delivered_signal and forward SIGTERM to the child
so the proxy leaves its poll() loop through the normal path and
ul_pty_cleanup() restores the saved terminal settings. The default
disposition of SIGALRM is termination, so this preserves the previous
outcome while adding the cleanup.

None of script, su --pty or runuser --pty arms SIGALRM internally on this
code path.

This addresses the deterministic SIGALRM path reported in #4499. The
separate, much narrower window where a terminating signal arrives
between ul_pty_setup() (raw mode on) and ul_pty_signals_setup() (signals
blocked) is not addressed here; closing it requires reworking the signal
mask contract between those two calls.

Partially fixes: https://github.com/util-linux/util-linux/issues/4499
Signed-off-by: lzwind <liuzheng@uniontech.com>
lib/pty-session.c

index ba46ba2430fdeae5e61d0bdda739f1292a640b8b..12d7326a2ab0510d87eb321a0b237be0be0a72df 100644 (file)
@@ -582,6 +582,8 @@ static int handle_signal(struct ul_pty *pty, int fd)
                                                        &info, (void *) &pty->win);
                }
                break;
+       case SIGALRM:
+               FALLTHROUGH;
        case SIGHUP:
                FALLTHROUGH;
        case SIGTERM:
@@ -589,7 +591,7 @@ static int handle_signal(struct ul_pty *pty, int fd)
        case SIGINT:
                FALLTHROUGH;
        case SIGQUIT:
-               DBG_OBJ(SIG, pty, ul_debug(" get signal SIG{TERM,INT,QUIT}"));
+               DBG_OBJ(SIG, pty, ul_debug(" get signal SIG{ALRM,HUP,TERM,INT,QUIT}"));
                pty->delivered_signal = info.ssi_signo;
                /* Child termination is going to generate SIGCHLD (see above) */
                if (pty->child > 0)