From a75e3011d9f0ebfd3b9adf4e41d7d377fb4cdc29 Mon Sep 17 00:00:00 2001 From: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> Date: Mon, 27 Apr 2026 11:57:37 +0200 Subject: [PATCH] remote: validate snappy decoded length before allocation in read endpoint Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> --- storage/remote/codec.go | 8 ++++++++ storage/remote/codec_test.go | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/storage/remote/codec.go b/storage/remote/codec.go index 80bb811500..634244d8b4 100644 --- a/storage/remote/codec.go +++ b/storage/remote/codec.go @@ -67,6 +67,14 @@ func DecodeReadRequest(r *http.Request) (*prompb.ReadRequest, error) { return nil, err } + decodedLen, err := snappy.DecodedLen(compressed) + if err != nil { + return nil, err + } + if decodedLen > decodeReadLimit { + return nil, fmt.Errorf("snappy: decoded length %d exceeds limit %d", decodedLen, decodeReadLimit) + } + reqBuf, err := snappy.Decode(nil, compressed) if err != nil { return nil, err diff --git a/storage/remote/codec_test.go b/storage/remote/codec_test.go index c92f0f8cde..b3e9580d8d 100644 --- a/storage/remote/codec_test.go +++ b/storage/remote/codec_test.go @@ -17,6 +17,7 @@ import ( "bytes" "fmt" "io" + "net/http" "sync" "testing" @@ -616,6 +617,17 @@ func TestMergeLabels(t *testing.T) { } } +func TestDecodeReadRequestTooLarge(t *testing.T) { + // 5-byte snappy stream whose header claims 256 MiB decoded length, + // well above decodeReadLimit (32 MiB). + bomb := []byte{0x80, 0x80, 0x80, 0x80, 0x01} + req, err := http.NewRequest(http.MethodPost, "/", bytes.NewReader(bomb)) + require.NoError(t, err) + + _, err = DecodeReadRequest(req) + require.ErrorContains(t, err, "exceeds limit") +} + func TestDecodeWriteRequest(t *testing.T) { buf, _, _, err := buildWriteRequest(nil, writeRequestFixture.Timeseries, nil, nil, nil, nil, "snappy") require.NoError(t, err)