diff --git a/CHANGELOG.md b/CHANGELOG.md index 8744a50d3c4..fa9098fedba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ - [#8900](https://github.com/influxdata/influxdb/issues/8900): Don't assume `which` is present in package post-install script. - [#8908](https://github.com/influxdata/influxdb/issues/8908): Fix missing man pages in new packaging output - [#8909](https://github.com/influxdata/influxdb/issues/8909): Fix use of `INFLUXD_OPTS` in service file +- [#8952](https://github.com/influxdata/influxdb/issues/8952): Fix WAL panic: runtime error: makeslice: cap out of range ## v1.3.4 [unreleased] diff --git a/tsdb/engine/tsm1/wal.go b/tsdb/engine/tsm1/wal.go index 7b7bda951aa..ac6822a3de3 100644 --- a/tsdb/engine/tsm1/wal.go +++ b/tsdb/engine/tsm1/wal.go @@ -772,6 +772,10 @@ func (w *WriteWALEntry) UnmarshalBinary(b []byte) error { nvals := int(binary.BigEndian.Uint32(b[i : i+4])) i += 4 + if nvals <= 0 || nvals > len(b) { + return ErrWALCorrupt + } + switch typ { case float64EntryType: if i+16*nvals > len(b) { diff --git a/tsdb/engine/tsm1/wal_test.go b/tsdb/engine/tsm1/wal_test.go index d94aa86e170..8602367277c 100644 --- a/tsdb/engine/tsm1/wal_test.go +++ b/tsdb/engine/tsm1/wal_test.go @@ -603,6 +603,52 @@ func TestWALWriter_Corrupt(t *testing.T) { } } +// Reproduces a `panic: runtime error: makeslice: cap out of range` when run with +// GOARCH=386 go test -run TestWALSegmentReader_Corrupt -v ./tsdb/engine/tsm1/ +func TestWALSegmentReader_Corrupt(t *testing.T) { + dir := MustTempDir() + defer os.RemoveAll(dir) + f := MustTempFile(dir) + w := tsm1.NewWALSegmentWriter(f) + + p4 := tsm1.NewValue(1, "string") + + values := map[string][]tsm1.Value{ + "cpu,host=A#!~#string": []tsm1.Value{p4, p4}, + } + + entry := &tsm1.WriteWALEntry{ + Values: values, + } + + typ, b := mustMarshalEntry(entry) + + // This causes the nvals field to overflow on 32 bit systems which produces a + // negative count and a panic when reading the segment. + b[25] = 255 + + if err := w.Write(typ, b); err != nil { + fatal(t, "write points", err) + } + + if err := w.Flush(); err != nil { + fatal(t, "flush", err) + } + + // Create the WAL segment reader. + if _, err := f.Seek(0, io.SeekStart); err != nil { + fatal(t, "seek", err) + } + + r := tsm1.NewWALSegmentReader(f) + defer r.Close() + + // Try to decode two entries. + for r.Next() { + r.Read() + } +} + func TestWriteWALSegment_UnmarshalBinary_WriteWALCorrupt(t *testing.T) { p1 := tsm1.NewValue(1, 1.1) p2 := tsm1.NewValue(1, int64(1))