Fix CVE-2019-9512 and CVE-2019-9514
authorDr. Tobias Quathamer <toddy@debian.org>
Thu, 15 Aug 2019 19:34:14 +0000 (21:34 +0200)
committerDr. Tobias Quathamer <toddy@debian.org>
Thu, 15 Aug 2019 19:48:59 +0000 (20:48 +0100)
Cherry-picked from upstream:
https://github.com/golang/go/commit/e152b01a468a1c18a290bf9aec52ccea7693c7f2

Gbp-Pq: Name 0005-Fix-CVE-2019-9512-and-CVE-2019-9514.patch

src/net/http/h2_bundle.go

index 2cd2b86df2787280d8a273340731438f5d2151dd..61824950f4d390e5f666afc59f4578328a4ac3f8 100644 (file)
@@ -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 {