vendor: fix x/crypto ssh channel.SendRequest spinloop on closed channel (golang/go#79658)#1143
Merged
Merged
Conversation
…145) diego-logging-client (tnz-96145) removed grpc.WithBlock() from NewIngressClient, making the loggregator dial non-blocking. ssh-proxy now starts successfully even when the loggregator server is unavailable and retries the connection in the background. The test "when the loggregator server isn't up → exits with non-zero status code" expected the old blocking behaviour. With the non-blocking dial ssh-proxy never exits, causing the test to time out. Update the assertion to verify the new correct behaviour: ssh-proxy starts and keeps running when the loggregator server is temporarily unavailable. Co-authored-by: Cursor <cursoragent@cursor.com>
1aecc70 to
76c29dd
Compare
kart2bc
previously approved these changes
Jun 2, 2026
Bump golang.org/x/crypto v0.52.0 → v0.52.1-0.20260528171630-4c4d20b72c2f
to pick up two upstream fixes for spinloops introduced by the CVE-2026-39830
security patch (3c7c869):
e3e62d9 ssh: fix spinloop in channel SendRequest drain on closed channel
4c4d20b ssh: fix spinloop in mux SendRequest drain on closed channel
Both fixes apply the comma-ok idiom to drain loops that spin forever when
ch.msg / m.globalResponses is already closed:
// Before
case <-ch.msg:
// After
case _, ok := <-ch.msg:
if !ok {
break drain
}
The spinloop caused session_channel_handler_windows2016_test.go:718
("the session is no longer usable") to hang ~59 minutes on Windows 2016
until the Ginkgo suite timeout fired. The failure was deterministic
across all three CI runs.
Neither fix is in a tagged release yet; the pseudo-version pins go.mod,
go.sum, and vendor/ to the exact commits so a future go mod vendor run
will not silently drop the fix. When upstream tags v0.53.0 the periodic
bump-dependencies job will upgrade cleanly over this.
Upstream references:
golang/go#79658
golang/crypto@e3e62d9 (channel fix)
golang/crypto@4c4d20b (mux fix)
Co-authored-by: Cursor <cursoragent@cursor.com>
76c29dd to
698218a
Compare
kart2bc
approved these changes
Jun 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
golang.org/x/crypto v0.52.0— introduced into this repo by 6c4f72a (v0.50.0 → v0.52.0) — shipped a security fix for CVE-2026-39830 (3c7c869 — "ssh: fix deadlock on unexpected channel responses"). That fix added drain loops inside both channel.SendRequest and mux.SendRequest to flush any stale buffered replies before a new request is sent. Both loops have the same bug:The loop does not use the comma-ok idiom (_, ok := <-ch.msg). When the underlying SSH channel has already been closed, ch.msg is a closed Go channel, and a receive from a closed channel always returns immediately with the zero value. The default arm is therefore never selected, and the loop spins at 100% CPU forever.
On Windows 2016 the server-side channel teardown completes fast enough that ch.msg is already closed before the caller's next SendRequest call. This caused the test at
src/code.cloudfoundry.org/diego-ssh/handlers/session_channel_handler_windows2016_test.go:718("the session is no longer usable") to hang for ~59 minutes until the Ginkgo suite timeout fired.
The failure was deterministic across all three CI runs.
Fix
This PR bumps golang.org/x/crypto in go.mod to pseudo-version v0.52.1-0.20260528171630-4c4d20b72c2f, which pins the vendor tree to the exact upstream commits that fix both spinloops:
e3e62d9 — "ssh: fix spinloop in channel SendRequest drain on closed channel" (golang/go#79658)
4c4d20b — "ssh: fix spinloop in mux SendRequest drain on closed channel"
The same fix applies symmetrically to mux.go's m.globalResponses drain loop.
Additional vendor changes
Because Go pseudo-versions are linear, v0.52.1-0.20260528171630-4c4d20b72c2f also includes the upstream auth-hardening commits that landed just before the spinloop fixes:

These are conservative hardening changes; none alter any SSH protocol behavior used by diego-ssh.
BOSH package specs
control.go introduces a new transitive import (golang.org/x/crypto/cryptobyte). The following BOSH package specs were updated to include the new dependency globs:
Durability
Using a go.mod pseudo-version rather than a raw vendor patch means the fix is durable:
The bump-dependencies periodic job runs go get -u, which will not downgrade from v0.52.1-... to v0.52.0 (pseudo-versions are treated as higher than the base tag).
When upstream tags v0.53.0 (which will include both spinloop fixes), the bump job will upgrade cleanly past the pseudo-version with no conflict.
Upstream references:
Backward Compatibility
Breaking Change? No
The change only affects behavior on an already-closed SSH channel — a case where the old code either returned io.EOF (pre-v0.52.0) or spun forever (v0.52.0 without this fix). Restoring a clean io.EOF return is strictly a bug fix and does not alter any public API or operator-visible behavior.
Notes