aboutsummaryrefslogtreecommitdiff
path: root/src/net/http
diff options
context:
space:
mode:
authorNicholas S. Husin <nsh@golang.org>2026-03-31 15:02:11 -0400
committerNicholas Husin <nsh@golang.org>2026-03-31 15:18:14 -0700
commite3a10fe3749eea3d7d5f284c3a1e57479131176f (patch)
tree60a419181715c4088366bdc179a2b59ccf8db398 /src/net/http
parent836b0984ee0b930c02ca62f9e8801f1016c9b253 (diff)
downloadgo-e3a10fe3749eea3d7d5f284c3a1e57479131176f.tar.xz
net/http/internal/http2: prevent hanging Transport due to bad SETTINGS frame
When processing SETTINGS frame, Transport currently only checks if the frame is valid for SETTINGS_ENABLE_CONNECT_PROTOCOL. As a result, a SETTINGS_MAX_FRAME_SIZE with the invalid value of 0 is erroneously accepted. This will then result in Transport being stuck in an infinite loop writing CONTINUATION frames. This CL fixes the issue by ensuring that SETTINGS frame are always validated, regardless of the SETTINGS parameter. Thanks to Marwan Atia (marwansamir688@gmail.com) for reporting this issue. Fixes #78476 Fixes CVE-2026-33814 Change-Id: I8b6219431e87454d34bca738fbcb59b66a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/761581 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Nicholas Husin <husin@google.com>
Diffstat (limited to 'src/net/http')
-rw-r--r--src/net/http/internal/http2/transport.go6
-rw-r--r--src/net/http/internal/http2/transport_test.go13
2 files changed, 16 insertions, 3 deletions
diff --git a/src/net/http/internal/http2/transport.go b/src/net/http/internal/http2/transport.go
index 36423b22df..2b04bed50a 100644
--- a/src/net/http/internal/http2/transport.go
+++ b/src/net/http/internal/http2/transport.go
@@ -2836,6 +2836,9 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
var seenMaxConcurrentStreams bool
err := f.ForeachSetting(func(s Setting) error {
+ if err := s.Valid(); err != nil {
+ return err
+ }
switch s.ID {
case SettingMaxFrameSize:
cc.maxFrameSize = s.Val
@@ -2867,9 +2870,6 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
cc.henc.SetMaxDynamicTableSize(s.Val)
cc.peerMaxHeaderTableSize = s.Val
case SettingEnableConnectProtocol:
- if err := s.Valid(); err != nil {
- return err
- }
// If the peer wants to send us SETTINGS_ENABLE_CONNECT_PROTOCOL,
// we require that it do so in the first SETTINGS frame.
//
diff --git a/src/net/http/internal/http2/transport_test.go b/src/net/http/internal/http2/transport_test.go
index 2e3dad3310..955c2208ad 100644
--- a/src/net/http/internal/http2/transport_test.go
+++ b/src/net/http/internal/http2/transport_test.go
@@ -5428,6 +5428,19 @@ func testTransportTLSNextProtoConnImmediateFailureUnused(t testing.TB) {
tc2.wantFrameType(FrameHeaders)
}
+func TestTransportDoNotHangOnZeroMaxFrameSize(t *testing.T) {
+ synctestTest(t, testTransportDoNotHangOnZeroMaxFrameSize)
+}
+func testTransportDoNotHangOnZeroMaxFrameSize(t testing.TB) {
+ tc := newTestClientConn(t)
+ tc.writeSettings(Setting{ID: SettingMaxFrameSize, Val: 0})
+ tc.wantFrameType(FrameSettings)
+
+ req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader("body"))
+ tc.roundTrip(req)
+ // Previously, https://go.dev/issue/78476 caused an infinite hang here.
+}
+
func TestExtendedConnectClientWithServerSupport(t *testing.T) {
t.Skip("https://go.dev/issue/53208 -- net/http needs to support the :protocol header")
SetDisableExtendedConnectProtocol(t, false)