174 lines
7.0 KiB
Diff
174 lines
7.0 KiB
Diff
|
|
From e152b01a468a1c18a290bf9aec52ccea7693c7f2 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Filippo Valsorda <filippo@golang.org>
|
||
|
|
Date: Mon, 12 Aug 2019 16:59:30 -0400
|
||
|
|
Subject: [PATCH] [release-branch.go1.11-security] net/http: update bundled
|
||
|
|
http2 to import security fix
|
||
|
|
|
||
|
|
Apply the following unpublished golang.org/x/net commit.
|
||
|
|
|
||
|
|
commit b1cc14aba47abf96f96818003fa4caad3a4b4e86
|
||
|
|
Author: Filippo Valsorda <filippo@golang.org>
|
||
|
|
Date: Sun Aug 11 02:12:18 2019 -0400
|
||
|
|
|
||
|
|
[release-branch.go1.11] http2: limit number of control frames in server send queue
|
||
|
|
|
||
|
|
An attacker could cause servers to queue an unlimited number of PING
|
||
|
|
ACKs or RST_STREAM frames by soliciting them and not reading them, until
|
||
|
|
the program runs out of memory.
|
||
|
|
|
||
|
|
Limit control frames in the queue to a few thousands (matching the limit
|
||
|
|
imposed by other vendors) by counting as they enter and exit the scheduler,
|
||
|
|
so the protection will work with any WriteScheduler.
|
||
|
|
|
||
|
|
Once the limit is exceeded, close the connection, as we have no way to
|
||
|
|
communicate with the peer.
|
||
|
|
|
||
|
|
Change-Id: I842968fc6ed3eac654b497ade8cea86f7267886b
|
||
|
|
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/525552
|
||
|
|
Reviewed-by: Brad Fitzpatrick <bradfitz@google.com>
|
||
|
|
(cherry picked from commit 589ad6cc5321fb68a90370348a241a5da0a2cc80)
|
||
|
|
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/526070
|
||
|
|
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
|
||
|
|
|
||
|
|
Fixes CVE-2019-9512 and CVE-2019-9514
|
||
|
|
Updates #33606
|
||
|
|
|
||
|
|
Change-Id: Iecedf1cc63ec7a1cd75661ec591d91ebc911cc64
|
||
|
|
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/526072
|
||
|
|
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
|
||
|
|
---
|
||
|
|
src/net/http/h2_bundle.go | 54 +++++++++++++++++++++++++++++++++++++++--------
|
||
|
|
1 file changed, 45 insertions(+), 9 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
|
||
|
|
index 2cd2b86..6182495 100644
|
||
|
|
--- a/src/net/http/h2_bundle.go
|
||
|
|
+++ b/src/net/http/h2_bundle.go
|
||
|
|
@@ -3835,10 +3835,11 @@ func (p *http2pipe) Done() <-chan struct{} {
|
||
|
|
}
|
||
|
|
|
||
|
|
const (
|
||
|
|
- http2prefaceTimeout = 10 * time.Second
|
||
|
|
- http2firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
|
||
|
|
- http2handlerChunkWriteSize = 4 << 10
|
||
|
|
- http2defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
|
||
|
|
+ http2prefaceTimeout = 10 * time.Second
|
||
|
|
+ http2firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
|
||
|
|
+ http2handlerChunkWriteSize = 4 << 10
|
||
|
|
+ http2defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
|
||
|
|
+ http2maxQueuedControlFrames = 10000
|
||
|
|
)
|
||
|
|
|
||
|
|
var (
|
||
|
|
@@ -3946,6 +3947,15 @@ func (s *http2Server) maxConcurrentStreams() uint32 {
|
||
|
|
return http2defaultMaxStreams
|
||
|
|
}
|
||
|
|
|
||
|
|
+// maxQueuedControlFrames is the maximum number of control frames like
|
||
|
|
+// SETTINGS, PING and RST_STREAM that will be queued for writing before
|
||
|
|
+// the connection is closed to prevent memory exhaustion attacks.
|
||
|
|
+func (s *http2Server) maxQueuedControlFrames() int {
|
||
|
|
+ // TODO: if anybody asks, add a Server field, and remember to define the
|
||
|
|
+ // behavior of negative values.
|
||
|
|
+ return http2maxQueuedControlFrames
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
type http2serverInternalState struct {
|
||
|
|
mu sync.Mutex
|
||
|
|
activeConns map[*http2serverConn]struct{}
|
||
|
|
@@ -4254,6 +4264,7 @@ type http2serverConn struct {
|
||
|
|
sawFirstSettings bool // got the initial SETTINGS frame after the preface
|
||
|
|
needToSendSettingsAck bool
|
||
|
|
unackedSettings int // how many SETTINGS have we sent without ACKs?
|
||
|
|
+ queuedControlFrames int // control frames in the writeSched queue
|
||
|
|
clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
|
||
|
|
advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
|
||
|
|
curClientStreams uint32 // number of open streams initiated by the client
|
||
|
|
@@ -4644,6 +4655,14 @@ func (sc *http2serverConn) serve() {
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+ // If the peer is causing us to generate a lot of control frames,
|
||
|
|
+ // but not reading them from us, assume they are trying to make us
|
||
|
|
+ // run out of memory.
|
||
|
|
+ if sc.queuedControlFrames > sc.srv.maxQueuedControlFrames() {
|
||
|
|
+ sc.vlogf("http2: too many control frames in send queue, closing connection")
|
||
|
|
+ return
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
// Start the shutdown timer after sending a GOAWAY. When sending GOAWAY
|
||
|
|
// with no error code (graceful shutdown), don't start the timer until
|
||
|
|
// all open streams have been completed.
|
||
|
|
@@ -4845,6 +4864,14 @@ func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) {
|
||
|
|
}
|
||
|
|
|
||
|
|
if !ignoreWrite {
|
||
|
|
+ if wr.isControl() {
|
||
|
|
+ sc.queuedControlFrames++
|
||
|
|
+ // For extra safety, detect wraparounds, which should not happen,
|
||
|
|
+ // and pull the plug.
|
||
|
|
+ if sc.queuedControlFrames < 0 {
|
||
|
|
+ sc.conn.Close()
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
sc.writeSched.Push(wr)
|
||
|
|
}
|
||
|
|
sc.scheduleFrameWrite()
|
||
|
|
@@ -4962,10 +4989,8 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
|
||
|
|
// If a frame is already being written, nothing happens. This will be called again
|
||
|
|
// when the frame is done being written.
|
||
|
|
//
|
||
|
|
-// If a frame isn't being written we need to send one, the best frame
|
||
|
|
-// to send is selected, preferring first things that aren't
|
||
|
|
-// stream-specific (e.g. ACKing settings), and then finding the
|
||
|
|
-// highest priority stream.
|
||
|
|
+// If a frame isn't being written and we need to send one, the best frame
|
||
|
|
+// to send is selected by writeSched.
|
||
|
|
//
|
||
|
|
// If a frame isn't being written and there's nothing else to send, we
|
||
|
|
// flush the write buffer.
|
||
|
|
@@ -4993,6 +5018,9 @@ func (sc *http2serverConn) scheduleFrameWrite() {
|
||
|
|
}
|
||
|
|
if !sc.inGoAway || sc.goAwayCode == http2ErrCodeNo {
|
||
|
|
if wr, ok := sc.writeSched.Pop(); ok {
|
||
|
|
+ if wr.isControl() {
|
||
|
|
+ sc.queuedControlFrames--
|
||
|
|
+ }
|
||
|
|
sc.startFrameWrite(wr)
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
@@ -5285,6 +5313,8 @@ func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
|
||
|
|
if err := f.ForeachSetting(sc.processSetting); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
+ // TODO: judging by RFC 7540, Section 6.5.3 each SETTINGS frame should be
|
||
|
|
+ // acknowledged individually, even if multiple are received before the ACK.
|
||
|
|
sc.needToSendSettingsAck = true
|
||
|
|
sc.scheduleFrameWrite()
|
||
|
|
return nil
|
||
|
|
@@ -9476,7 +9506,7 @@ type http2WriteScheduler interface {
|
||
|
|
|
||
|
|
// Pop dequeues the next frame to write. Returns false if no frames can
|
||
|
|
// be written. Frames with a given wr.StreamID() are Pop'd in the same
|
||
|
|
- // order they are Push'd.
|
||
|
|
+ // order they are Push'd. No frames should be discarded except by CloseStream.
|
||
|
|
Pop() (wr http2FrameWriteRequest, ok bool)
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -9520,6 +9550,12 @@ func (wr http2FrameWriteRequest) StreamID() uint32 {
|
||
|
|
return wr.stream.id
|
||
|
|
}
|
||
|
|
|
||
|
|
+// isControl reports whether wr is a control frame for MaxQueuedControlFrames
|
||
|
|
+// purposes. That includes non-stream frames and RST_STREAM frames.
|
||
|
|
+func (wr http2FrameWriteRequest) isControl() bool {
|
||
|
|
+ return wr.stream == nil
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
// DataSize returns the number of flow control bytes that must be consumed
|
||
|
|
// to write this entire frame. This is 0 for non-DATA frames.
|
||
|
|
func (wr http2FrameWriteRequest) DataSize() int {
|
||
|
|
--
|
||
|
|
1.9.4
|
||
|
|
|