Skip to content

Fix proxycommand hang when server closes before stdin closes#1647

Merged
tashian merged 1 commit into
masterfrom
fix/proxycommand-deadlock-1641
Jun 9, 2026
Merged

Fix proxycommand hang when server closes before stdin closes#1647
tashian merged 1 commit into
masterfrom
fix/proxycommand-deadlock-1641

Conversation

@tashian

@tashian tashian commented Jun 9, 2026

Copy link
Copy Markdown
Member

Fixes #1641 · Linear: PRE-124

Problem

step ssh proxycommand hangs ~60s when the SSH server closes the connection before the client has closed stdin — e.g. when the server rejects the session mid-stream (PAM account check fails after cert auth succeeds).

The deadlock is in proxyDirect: it spawns two copy goroutines and wg.Wait()s for both. When the server closes, the conn→stdout goroutine returns, but the stdin→conn goroutine stays blocked reading os.Stdin — which never reaches EOF because the SSH client holds the proxycommand's stdin open until the proxycommand exits. Neither side gives, so wg.Wait() blocks until an OS-level timeout reaps the process.

Fix

Return as soon as either direction finishes instead of waiting for both. For a proxycommand there's nothing left to do once one half of the SSH transport closes — returning lets the process exit and the OS reclaim the still-blocked goroutine. Replaced the sync.WaitGroup with a buffered done channel + <-done, and added defer conn.Close() so the surviving copy goroutine is also unblocked on the way out.

Testing

Extracted a testable proxyDirectWithIO(host, port, stdin, stdout) and added Test_proxyDirectWithIO_serverClosesBeforeStdin: a TCP server that sends data then closes, with a stdin that never EOFs. Verified it hangs the full timeout against the old logic (RED) and returns promptly after the fix (GREEN, race-clean). go build ./..., go vet, and the full command/ssh package pass.

🤖 Generated with Claude Code

proxyDirect waited for both copy goroutines via wg.Wait(). When the
server closes the connection mid-session, the stdin->conn goroutine
stays blocked reading a stdin that never reaches EOF (the ssh client
holds the proxycommand's stdin open until it exits), deadlocking until
an OS-level timeout reaps the process.

Return as soon as either direction finishes instead. Extracted a
testable proxyDirectWithIO and added a regression test.

Fixes #1641

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tashian tashian enabled auto-merge June 9, 2026 16:03
@tashian tashian changed the title Fix proxycommand hang when server closes before stdin closes PRE-124: Fix proxycommand hang when server closes before stdin closes Jun 9, 2026
@hslatman hslatman added this to the v0.30.3 milestone Jun 9, 2026
@hslatman hslatman changed the title PRE-124: Fix proxycommand hang when server closes before stdin closes Fix proxycommand hang when server closes before stdin closes Jun 9, 2026

@maraino maraino left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@tashian tashian merged commit 00b371a into master Jun 9, 2026
26 of 27 checks passed
@tashian tashian deleted the fix/proxycommand-deadlock-1641 branch June 9, 2026 17:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

step ssh proxycommand hangs ~60s when server closes connection before stdin closes

3 participants