mirror of
https://github.com/tailscale/tailscale.git
synced 2026-09-23 03:55:11 -04:00
k8s-operator/sessionrecording/spdy: don't pre-size header map from wire
Signed-off-by: chaosinthecrd <tom@tmlabs.co.uk>
This commit is contained in:
2 files changed
+31
-1
No files matched your search
@@ -222,7 +222,12 @@ func parseHeaders(decompressor io.Reader, log *zap.SugaredLogger) (http.Header,
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error determining num headers: %v", err)
|
||||
}
|
||||
h := make(http.Header, numHeaders)
|
||||
// numHeaders is attacker controlled, so it must not be used to pre-size the
|
||||
// map: a small frame can declare ~4 billion headers and make Go reserve
|
||||
// gigabytes of bucket storage before a single header is read. The map grows
|
||||
// itself fine, and the io.LimitReader above bounds how many we can actually
|
||||
// read.
|
||||
h := make(http.Header)
|
||||
for range numHeaders {
|
||||
name, err := readLenBytes()
|
||||
if err != nil {
|
||||
|
||||
@@ -261,6 +261,31 @@ func Test_spdyFrame_parseHeaders_decompressionBomb(t *testing.T) {
|
||||
if got.Get("x") != strings.Repeat("A", 16) {
|
||||
t.Fatalf("unexpected header value: got %q", got.Get("x"))
|
||||
}
|
||||
|
||||
// A block declaring a huge number of headers must be rejected without
|
||||
// pre-sizing a map for that many entries. The declared count is only 4
|
||||
// bytes, so it slips under the io.LimitReader cap; the fix is to not feed
|
||||
// it to make(). Without that fix this does not fail, it OOMs the binary.
|
||||
countBomb := bytes.NewBuffer(nil)
|
||||
writeControlFramePayloadBeforeHeaders(t, countBomb, SYN_STREAM, 1)
|
||||
cw, err := zlib.NewWriterLevelDict(countBomb, zlib.BestCompression, spdyTxtDictionary)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating zlib writer: %v", err)
|
||||
}
|
||||
if err := binary.Write(cw, binary.BigEndian, uint32(0xFFFFFFFF)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cw.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var z3 zlibReader
|
||||
sf3 := &spdyFrame{Ctrl: true, Type: SYN_STREAM, Payload: countBomb.Bytes()}
|
||||
if _, err := sf3.parseHeaders(&z3, zl.Sugar()); err == nil {
|
||||
t.Fatal("parseHeaders accepted a block declaring 0xFFFFFFFF headers")
|
||||
}
|
||||
}
|
||||
|
||||
// Test_spdyFrame_ParseRand calls spdyFrame.Parse with randomly generated bytes
|
||||
|
||||
Reference in new issue
Block a user