From 5e746e4e88adfe44a69764e3ac99d2d01f2224db Mon Sep 17 00:00:00 2001 From: Oleg Zaytsev Date: Wed, 24 Nov 2021 10:56:37 +0100 Subject: [PATCH] Check postings bytes length when decoding (#9766) Added validation to expected postings length compared to the bytes slice length. With 32bit postings, we expect to have 4 bytes per each posting. If the number doesn't add up, we know that the input data is not compatible with our code (maybe it's cut, or padded with trash, or even written in a different coded). This is needed in downstream projects to correctly identify cached postings written with an unknown codec, but it's also a good idea to validate it here. Signed-off-by: Oleg Zaytsev --- tsdb/index/index.go | 9 ++++++++- tsdb/index/index_test.go | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tsdb/index/index.go b/tsdb/index/index.go index 957e468f6..0d2981385 100644 --- a/tsdb/index/index.go +++ b/tsdb/index/index.go @@ -18,6 +18,7 @@ import ( "bytes" "context" "encoding/binary" + "fmt" "hash" "hash/crc32" "io" @@ -1782,7 +1783,13 @@ func (dec *Decoder) Postings(b []byte) (int, Postings, error) { d := encoding.Decbuf{B: b} n := d.Be32int() l := d.Get() - return n, newBigEndianPostings(l), d.Err() + if d.Err() != nil { + return 0, nil, d.Err() + } + if len(l) != 4*n { + return 0, nil, fmt.Errorf("unexpected postings length, should be %d bytes for %d postings, got %d bytes", 4*n, n, len(l)) + } + return n, newBigEndianPostings(l), nil } // LabelNamesOffsetsFor decodes the offsets of the name symbols for a given series. diff --git a/tsdb/index/index_test.go b/tsdb/index/index_test.go index c859dbb47..e2764ff26 100644 --- a/tsdb/index/index_test.go +++ b/tsdb/index/index_test.go @@ -560,3 +560,8 @@ func TestSymbols(t *testing.T) { } require.NoError(t, iter.Err()) } + +func TestDecoder_Postings_WrongInput(t *testing.T) { + _, _, err := (&Decoder{}).Postings([]byte("the cake is a lie")) + require.Error(t, err) +}