[Bug 3995] New: readpassphrase() spins at 100% CPU forever when SIGTTIN/SIGTTOU is SIG_IGN and no controlling TTY is available
bugzilla-daemon at mindrot.org
bugzilla-daemon at mindrot.org
Sun Aug 23 04:43:12 AEST 2026
https://bugzilla.mindrot.org/show_bug.cgi?id=3995
Bug ID: 3995
Summary: readpassphrase() spins at 100% CPU forever when
SIGTTIN/SIGTTOU is SIG_IGN and no controlling TTY is
available
Product: Portable OpenSSH
Version: 10.5p1
Hardware: Other
OS: Linux
Status: NEW
Severity: normal
Priority: P5
Component: ssh-add
Assignee: unassigned-bugs at mindrot.org
Reporter: martin.monperrus at gnieh.org
Created attachment 3983
--> https://bugzilla.mindrot.org/attachment.cgi?id=3983&action=edit
tentative patch for ssh-add 100% CPU forever
Summary
-------
When an OpenSSH tool that calls readpassphrase() (ssh-add is the common
case) is started with no controlling TTY, in a background process
group,
and with SIGTTIN and/or SIGTTOU already set to SIG_IGN by its parent
(e.g.
a systemd unit, or any supervisor/daemon that ignores job-control
signals), readpassphrase() spins at ~100% CPU indefinitely. It never
prints a prompt and never returns, so the caller hangs forever with no
way to detect or recover from the failure.
Root cause
----------
In openbsd-compat/readpassphrase.c, the signal handler for SIGTSTP,
SIGTTIN and SIGTTOU always sets need_restart = 1:
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
need_restart = 1;
readpassphrase() opens /dev/tty and attempts to read from it. Because
the
process is in a background process group, this raises SIGTTIN (or
SIGTTOU on the subsequent write of the prompt). The handler records the
signal and sets need_restart. readpassphrase() then restores the
*original* (saved) disposition for that signal — which is SIG_IGN in
this
scenario — and re-raises it via kill(getpid(), sig). Because the
disposition is now SIG_IGN, that kill() is a silent no-op: the
read/write
condition that caused SIGTTIN/SIGTTOU in the first place is never
resolved (there is still no controlling TTY to become the foreground
process group of). Since need_restart was already set, execution does
"goto restart", which reopens /dev/tty, writes the prompt again, hits
SIGTTIN/SIGTTOU again, and repeats forever at maximum CPU with no
prompt ever reaching a terminal and no error ever returned to the
caller.
This is distinct from bug 2619.
Steps to reproduce
------------------
1. Start a process tree with a controlling PTY (session leader in the
foreground process group).
2. Set SIGTTIN and SIGTTOU to SIG_IGN in a supervisor process
(simulating e.g. a systemd service unit).
3. Fork ssh-add as a child in its *own*, background process group (so
it
inherits the SIG_IGN dispositions but is not the foreground group of
the PTY), pointed at any passphrase-protected key.
4. Observe ssh-add immediately pin one CPU core at ~100% and never
exit,
never prompt, never time out.
Tentative patch attached
--
You are receiving this mail because:
You are watching the assignee of the bug.
More information about the openssh-bugs
mailing list