Skip to content

Commit 0a43f88

Browse files
neildcagedmantis
authored andcommitted
[internal-branch.go1.18-vendor] http2: handle server errors after sending GOAWAY
The HTTP/2 server uses serverConn.goAwayCode to track whether a connection has encountered a fatal error. If an error is encountered after sending a ErrCodeNo GOAWAY, upgrade goAwayCode to reflect the error status of the connection. Fixes an issue where a server connection could hang forever waiting for a clean shutdown that was preempted by a subsequent fatal error. Fixes CVE-2022-27664 For golang/go#54658 For golang/go#53977 Change-Id: I165b81ab53176c77a68c42976030499d57bb05d3 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1413887 Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/net/+/428735 Run-TryBot: Damien Neil <[email protected]> Reviewed-by: Carlos Amedee <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/net/+/428736 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 491a49a commit 0a43f88

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

http2/server.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,9 @@ func (sc *serverConn) startGracefulShutdownInternal() {
13341334
func (sc *serverConn) goAway(code ErrCode) {
13351335
sc.serveG.check()
13361336
if sc.inGoAway {
1337+
if sc.goAwayCode == ErrCodeNo {
1338+
sc.goAwayCode = code
1339+
}
13371340
return
13381341
}
13391342
sc.inGoAway = true
@@ -2546,8 +2549,9 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
25462549
// prior to the headers being written. If the set of trailers is fixed
25472550
// or known before the header is written, the normal Go trailers mechanism
25482551
// is preferred:
2549-
// https://golang.org/pkg/net/http/#ResponseWriter
2550-
// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
2552+
//
2553+
// https://golang.org/pkg/net/http/#ResponseWriter
2554+
// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
25512555
const TrailerPrefix = "Trailer:"
25522556

25532557
// promoteUndeclaredTrailers permits http.Handlers to set trailers

http2/server_test.go

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2721,8 +2721,9 @@ func readBodyHandler(t *testing.T, want string) func(w http.ResponseWriter, r *h
27212721
}
27222722

27232723
// TestServerWithCurl currently fails, hence the LenientCipherSuites test. See:
2724-
// https://github.com/tatsuhiro-t/nghttp2/issues/140 &
2725-
// http://sourceforge.net/p/curl/bugs/1472/
2724+
//
2725+
// https://github.com/tatsuhiro-t/nghttp2/issues/140 &
2726+
// http://sourceforge.net/p/curl/bugs/1472/
27262727
func TestServerWithCurl(t *testing.T) { testServerWithCurl(t, false) }
27272728
func TestServerWithCurl_LenientCipherSuites(t *testing.T) { testServerWithCurl(t, true) }
27282729

@@ -4367,3 +4368,46 @@ func TestNoErrorLoggedOnPostAfterGOAWAY(t *testing.T) {
43674368
t.Error("got protocol error")
43684369
}
43694370
}
4371+
4372+
func TestProtocolErrorAfterGoAway(t *testing.T) {
4373+
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
4374+
io.Copy(io.Discard, r.Body)
4375+
})
4376+
defer st.Close()
4377+
4378+
st.greet()
4379+
content := "some content"
4380+
st.writeHeaders(HeadersFrameParam{
4381+
StreamID: 1,
4382+
BlockFragment: st.encodeHeader(
4383+
":method", "POST",
4384+
"content-length", strconv.Itoa(len(content)),
4385+
),
4386+
EndStream: false,
4387+
EndHeaders: true,
4388+
})
4389+
st.writeData(1, false, []byte(content[:5]))
4390+
4391+
_, err := st.readFrame()
4392+
if err != nil {
4393+
st.t.Fatal(err)
4394+
}
4395+
4396+
// Send a GOAWAY with ErrCodeNo, followed by a bogus window update.
4397+
// The server should close the connection.
4398+
if err := st.fr.WriteGoAway(1, ErrCodeNo, nil); err != nil {
4399+
t.Fatal(err)
4400+
}
4401+
if err := st.fr.WriteWindowUpdate(0, 1<<31-1); err != nil {
4402+
t.Fatal(err)
4403+
}
4404+
4405+
for {
4406+
if _, err := st.readFrame(); err != nil {
4407+
if err != io.EOF {
4408+
t.Errorf("unexpected readFrame error: %v", err)
4409+
}
4410+
break
4411+
}
4412+
}
4413+
}

0 commit comments

Comments
 (0)