From: lzwind Date: Fri, 24 Jul 2026 13:00:15 +0000 (+0800) Subject: pty-session: handle SIGALRM instead of aborting X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2d05ed224ee5cb72c578ee70f08f9c28ae6c5222;p=thirdparty%2Futil-linux.git pty-session: handle SIGALRM instead of aborting 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 --- diff --git a/lib/pty-session.c b/lib/pty-session.c index ba46ba243..12d7326a2 100644 --- a/lib/pty-session.c +++ b/lib/pty-session.c @@ -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)