Files
tailscale/ssh/tailssh
Sachin NeneandClaude Opus 5 af08ffa4d2 ssh/tailssh: dup the pty master with F_DUPFD_CLOEXEC (#21342)
launchProcess duplicated the pty master with syscall.Dup, which is a
plain dup(2) and does not set FD_CLOEXEC. The original master from
pty.Open is CLOEXEC (os.OpenFile), but the dup is not, and it stays
open in tailscaled until the session's stdout copier closes it.

Because child processes are started with os/exec, which relies on
FD_CLOEXEC to drop fds, every other SSH session started while this one
is alive inherits the dup'd master. It then survives the incubator's
exec into login, the user's shell, and everything the shell runs.

When the original session disconnects, tailscaled closes its own copies
but the leaked copies in other sessions' process trees keep the pty
open: the slave never hangs up, nobody reads the master, and any process
writing to that tty blocks forever once the buffer fills. On a host with
a long-lived tmux server this shows up as every tmux command hanging,
with the server stuck in n_tty_write on a dead client's tty.

Use F_DUPFD_CLOEXEC so the dup is never inherited across exec.

Fixes #21343

Signed-off-by: Sachin Nene <sachin@corvex.ai>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-16 17:45:34 -07:00
..
2026-04-10 10:48:50 -07:00