diff --git a/bfe_http2/frame.go b/bfe_http2/frame.go index 33394e66..d5174b77 100644 --- a/bfe_http2/frame.go +++ b/bfe_http2/frame.go @@ -1504,6 +1504,7 @@ func (fr *Framer) readMetaFrame(f *HeadersFrame) (*MetaHeadersFrame, error) { hdec.SetEmitEnabled(false) mh.Truncated = true state.H2ErrMaxHeaderListSize.Inc(1) + remainSize = 0 return maxHeaderListSizeError{ streamID: f.FrameHeader.StreamID, curHeaderListSize: fr.maxHeaderListSize() - remainSize + size, @@ -1525,6 +1526,35 @@ func (fr *Framer) readMetaFrame(f *HeadersFrame) (*MetaHeadersFrame, error) { var err error for { frag := hc.HeaderBlockFragment() + + // Avoid parsing large amounts of headers that we will then discard. + // If the sender exceeds the max header list size by too much, + // skip parsing the fragment and close the connection. + // + // "Too much" is either any CONTINUATION frame after we've already + // exceeded the max header list size (in which case remainSize is 0), + // or a frame whose encoded size is more than twice the remaining + // header list bytes we're willing to accept. + if int64(len(frag)) > int64(2*remainSize) { + if VerboseLogs { + log.Printf("http2: header list too large") + } + // It would be nice to send a RST_STREAM before sending the GOAWAY, + // but the structure of the server's frame writer makes this difficult. + return nil, ConnectionError{ErrCodeProtocol, "http2: header list too large"} + } + + // Also close the connection after any CONTINUATION frame following an + // invalid header, since we stop tracking the size of the headers after + // an invalid one. + if invalid != nil { + if VerboseLogs { + log.Printf("http2: invalid header: %v", invalid) + } + // It would be nice to send a RST_STREAM before sending the GOAWAY, + // but the structure of the server's frame writer makes this difficult. + return nil, ConnectionError{ErrCodeProtocol, fmt.Sprintf("http2: invalid header: %v", invalid)} + } blockSize += len(frag) if _, err = hdec.Write(frag); err != nil { // do not return ConnectionError err type, diff --git a/bfe_http2/frame_test.go b/bfe_http2/frame_test.go index 04d20ed7..e6b2d576 100644 --- a/bfe_http2/frame_test.go +++ b/bfe_http2/frame_test.go @@ -931,7 +931,7 @@ func TestMetaFrameHeader(t *testing.T) { maxHeaderListSize: (1 << 10) / 2, want: maxHeaderListSizeError{ streamID: 1, - curHeaderListSize: 536, + curHeaderListSize: 550, maxHeaderListSize: 512, }, }, @@ -1033,7 +1033,7 @@ func TestMetaFrameHeader(t *testing.T) { } return fmt.Sprintf("value %#v", v) } - t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want)) + t.Errorf(" %s:\n got: %v\nwant: %s", name, str(got), str(tt.want)) } if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) { t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason)