Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30,083 changes: 30,083 additions & 0 deletions SPECS/moby-engine/CVE-2026-39821.patch

Large diffs are not rendered by default.

61 changes: 61 additions & 0 deletions SPECS/moby-engine/CVE-2026-39827.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
From 6c195c8a97ae3d91a366ebdd7787d5faa64bf42a Mon Sep 17 00:00:00 2001
From: Nicola Murino <nicola.murino@gmail.com>
Date: Sun, 1 Mar 2026 11:49:28 +0100
Subject: [PATCH] ssh: prevent memory leak when rejecting channels

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.

Fixes golang/go#35127
Fixes CVE-2026-39827

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>

Upstream Patch Reference: https://github.com/golang/crypto/commit/6c195c8a97ae3d91a366ebdd7787d5faa64bf42a.patch
---
vendor/golang.org/x/crypto/ssh/channel.go | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go
index 3967b65..77bac19 100644
--- a/vendor/golang.org/x/crypto/ssh/channel.go
+++ b/vendor/golang.org/x/crypto/ssh/channel.go
@@ -536,7 +536,17 @@ func (ch *channel) Reject(reason RejectionReason, message string) error {
Language: "en",
}
ch.decided = true
- return ch.sendMessage(reject)
+ err := ch.sendMessage(reject)
+
+ // Remove the channel from the mux to prevent memory leaks.
+ // Do not call ch.close() here: no goroutine holds a reference to a
+ // rejected channel's internal channels (msg, incomingRequests), so
+ // removing it from chanList is sufficient for GC. Calling close()
+ // would race with the mux loop goroutine (handlePacket or dropAll),
+ // causing a panic from closing an already-closed channel.
+ ch.mux.chanList.remove(ch.localId)
+
+ return err
}

func (ch *channel) Read(data []byte) (int, error) {
--
2.45.4

51 changes: 51 additions & 0 deletions SPECS/moby-engine/CVE-2026-39829.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
From 890731877d85f71cfdc9554e7a27fec4684fc4c4 Mon Sep 17 00:00:00 2001
From: Nicola Murino <nicola.murino@gmail.com>
Date: Sun, 1 Feb 2026 13:10:56 +0100
Subject: [PATCH] ssh: reject RSA keys with excessively large moduli

Previously, the RSA key parser accepted keys with arbitrary modulus
sizes. Processing keys with extremely large moduli (e.g., > 8192 bits)
can consume excessive CPU resources during verification, potentially
leading to a Denial of Service (DoS).

This change introduces a limit of 8192 bits for the RSA modulus in
parseRSA, rejecting keys that exceed this size in line with the limit
enforced by crypto/tls.

This issue was found during a security audit by NCC Group Cryptography
Services, sponsored by Teleport.

Fixes golang/go#79565
Fixes CVE-2026-39829

Change-Id: Ibdddad1859a4d9db5c9f052d06c82f29bfc2e5e5
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/781641
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>
Reviewed-by: Roland Shoemaker <roland@golang.org>

Upstream Patch Reference: https://github.com/golang/crypto/commit/890731877d85f71cfdc9554e7a27fec4684fc4c4.patch
---
vendor/golang.org/x/crypto/ssh/keys.go | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
index df4ebda..defcb49 100644
--- a/vendor/golang.org/x/crypto/ssh/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -449,6 +449,12 @@ func parseRSA(in []byte) (out PublicKey, rest []byte, err error) {
return nil, nil, err
}

+ // 8192 bits is also the maximum RSA key size accepted by crypto/tls for
+ // signature verification:
+ // https://github.com/golang/go/blob/69801b25/src/crypto/tls/handshake_client.go#L1096
+ if w.N.BitLen() > 8192 {
+ return nil, nil, errors.New("ssh: rsa modulus too large")
+ }
if w.E.BitLen() > 24 {
return nil, nil, errors.New("ssh: exponent too large")
}
--
2.45.4

105 changes: 105 additions & 0 deletions SPECS/moby-engine/CVE-2026-39830.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
From 4e7a7384ecbc8d519f6f4c11b36fa9d761fc8946 Mon Sep 17 00:00:00 2001
From: Nicola Murino <nicola.murino@gmail.com>
Date: Sun, 25 Jan 2026 19:08:01 +0100
Subject: [PATCH] ssh: fix deadlock on unexpected global responses

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.

Fixes golang/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>

Upstream Patch Reference: https://github.com/TheDegenerateDev5150/crypto/commit/4e7a7384ecbc8d519f6f4c11b36fa9d761fc8946.patch

---
vendor/golang.org/x/crypto/ssh/mux.go | 36 ++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go
index d2d24c6..3bc4afb 100644
--- a/vendor/golang.org/x/crypto/ssh/mux.go
+++ b/vendor/golang.org/x/crypto/ssh/mux.go
@@ -91,9 +91,10 @@ type mux struct {

incomingChannels chan NewChannel

- globalSentMu sync.Mutex
- globalResponses chan interface{}
- incomingRequests chan *Request
+ globalSentMu sync.Mutex
+ globalSentPending atomic.Bool
+ globalResponses chan interface{}
+ incomingRequests chan *Request

errCond *sync.Cond
err error
@@ -141,6 +142,24 @@ func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []
if wantReply {
m.globalSentMu.Lock()
defer m.globalSentMu.Unlock()
+
+ // Open the gate so that responses arriving while this request is in
+ // flight are allowed to reach globalResponses. Any response arriving
+ // while no request is pending is dropped by handleGlobalPacket.
+ m.globalSentPending.Store(true)
+ defer m.globalSentPending.Store(false)
+
+ // Drain any spurious responses that may have been buffered. This prevents
+ // a previously buffered unexpected response from being consumed instead
+ // of the actual response for this request.
+ drain:
+ for {
+ select {
+ case <-m.globalResponses:
+ default:
+ break drain
+ }
+ }
}

if err := m.sendMessage(globalRequestMsg{
@@ -267,7 +286,16 @@ func (m *mux) handleGlobalPacket(packet []byte) error {
mux: m,
}
case *globalRequestSuccessMsg, *globalRequestFailureMsg:
- m.globalResponses <- msg
+ // Drop responses that arrive when no SendRequest is waiting, to
+ // prevent a malicious peer from staging responses for a future
+ // caller.
+ if !m.globalSentPending.Load() {
+ return nil
+ }
+ select {
+ case m.globalResponses <- msg:
+ default:
+ }
default:
panic(fmt.Sprintf("not a global message %#v", msg))
}
--
2.45.4

Loading
Loading