Previously, the mux implementation handled global request responses by
blocking until the response could be sent to the globalResponses channel.
Since this channel has a buffer size of 1, unsolicited responses from a
server (or responses arriving after a timeout) would fill the buffer.
Subsequent unsolicited responses would block handleGlobalPacket, stalling
the entire connection's read loop and causing a denial of service.
This change modifies handleGlobalPacket to use a non-blocking send. If
no goroutine is waiting for a response (or the buffer is full), the
message is dropped. This aligns with OpenSSH behavior, which ignores
unexpected global responses.
Additionally, SendRequest now drains the globalResponses channel after
acquiring the mutex but before sending the request. This ensures that
any stale responses or "spam" buffered just before the lock was acquired
are discarded, preventing race conditions where a legitimate request
might otherwise consume an unrelated response.
This issue was found during a security audit by NCC Group Cryptography
Services, sponsored by Teleport.
Fixesgolang/go#79564
Fixes CVE-2026-39830
Change-Id: Ia0c46355203d557eadcd432c10b87c8a044e1089
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/781640
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Neal Patel <nealpatel@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
When a server rejects an incoming channel request via
NewChannel.Reject, the channel is left in the multiplexer's
channel list. Because the channel is never explicitly removed or
closed, its internal buffers and sync primitives remain allocated
for the lifetime of the SSH connection.
A malicious client could exploit this behavior by repeatedly
requesting to open channels that are destined to be rejected,
causing unbounded memory growth and potentially leading to a
Denial of Service (DoS) via resource exhaustion.
This change fixes the leak by calling ch.mux.chanList.remove
within the Reject method, removing the channel from the list and allowing the
garbage collector to reclaim the associated memory immediately.
Fixesgolang/go#35127
Fixes CVE-2026-3982
Change-Id: Iaa177f5dfd151812dd404e528a4a1c77527a0e29
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/781320
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Nicholas Husin <nsh@golang.org>
Reviewed-by: Nicholas Husin <husin@google.com>
Sending a window adjustment after every read is unnecessarily chatty,
especially with a series of small reads like with TTY interactions.
Copy OpenSSH's logic for deferring these, which seemingly hasn't changed
since 2007. Note that since channelWindowSize and c.maxIncomingPayload
are currently constants here, the two checks could be combined into a
single check for c.myWindow < 2 MiB - 96 KiB (with the current values
of the constants).
Fixesgolang/go#57424.
Change-Id: Ifcef5be76fcc3f0b1a6dc396096bed9c50d64f21
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/459915
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Commit-Queue: Nicola Murino <nicola.murino@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
rfc4254 section 5.4 states that channel request messages sent to an
unrecognized channel should be replied with a `SSH_MSG_CHANNEL_FAILURE`,
rather than erring out and closing the mux. This can occur with servers
like openssh-portable, which can begin to close a channel and also use
that channel for keepalives before it has received a closed response
from the client.
Fixesgolang/go#38908
Change-Id: Id68b77e16b2889d3a21d505ed8018f9f457e067a
GitHub-Last-Rev: 8a92f87dc30697d9e3805af695efdf1b1dc8409b
GitHub-Pull-Request: golang/crypto#136
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/232659
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
The extra Close call runs in a separate goroutine, and races with the
deferred Close call, leading to test flakes if the extra call fails
Change-Id: Ia1a2fb3932906da7cd0a8854b55f82785bb33716
Reviewed-on: https://go-review.googlesource.com/104335
Run-TryBot: Han-Wen Nienhuys <hanwen@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Test that different extended data streams within a channel are
thread-safe.
benchmark old MB/s new MB/s speedup
BenchmarkEndToEnd 79.26 87.98 1.11x
benchmark old allocs new allocs delta
BenchmarkEndToEnd 110 73 -33.64%
benchmark old bytes new bytes delta
BenchmarkEndToEnd 2605720 1299768 -50.12%
LGTM=dave, jpsugar
R=agl, dave, jpsugar
CC=golang-codereviews
https://golang.org/cl/136420043