mirror of
https://github.com/tailscale/tailscale.git
synced 2026-10-29 22:49:17 -04:00
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>