lib/storage: prevent from infinite loop if {__graphite__="..."} filter matches a metric name with *, [ or { chars

The idea has been borrowed from https://github.com/VictoriaMetrics/VictoriaMetrics/pull/1137
This commit is contained in:
Aliaksandr Valialkin 2021-03-18 14:52:49 +02:00
parent e03233f441
commit 4443254fb9
2 changed files with 25 additions and 18 deletions

View File

@ -9,6 +9,8 @@
* `process_resident_memory_peak_bytes` - peak RSS usage for the process. * `process_resident_memory_peak_bytes` - peak RSS usage for the process.
* `process_virtual_memory_peak_bytes` - peak virtual memory usage for the process. * `process_virtual_memory_peak_bytes` - peak virtual memory usage for the process.
* BUGFIX: prevent from infinite loop on `{__graphite__="..."}` filters when a metric name contains `*`, `{` or `[` chars.
# [v1.56.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.56.0) # [v1.56.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.56.0)

View File

@ -1,6 +1,7 @@
package storage package storage
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -15,6 +16,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/cgroup" "github.com/VictoriaMetrics/VictoriaMetrics/lib/cgroup"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding" "github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime" "github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
@ -1122,14 +1124,16 @@ func (s *Storage) SearchTagValueSuffixes(accountID, projectID uint32, tr TimeRan
} }
// SearchGraphitePaths returns all the matching paths for the given graphite query on the given tr. // SearchGraphitePaths returns all the matching paths for the given graphite query on the given tr.
//
// If more than maxPaths paths is found, then only the first maxPaths paths is returned.
func (s *Storage) SearchGraphitePaths(accountID, projectID uint32, tr TimeRange, query []byte, maxPaths int, deadline uint64) ([]string, error) { func (s *Storage) SearchGraphitePaths(accountID, projectID uint32, tr TimeRange, query []byte, maxPaths int, deadline uint64) ([]string, error) {
queryStr := string(query) return s.searchGraphitePaths(accountID, projectID, tr, nil, query, maxPaths, deadline)
n := strings.IndexAny(queryStr, "*[{") }
func (s *Storage) searchGraphitePaths(accountID, projectID uint32, tr TimeRange, qHead, qTail []byte, maxPaths int, deadline uint64) ([]string, error) {
n := strings.IndexAny(bytesutil.ToUnsafeString(qTail), "*[{")
if n < 0 { if n < 0 {
// Verify that the query matches a metric name. // Verify that qHead matches a metric name.
suffixes, err := s.SearchTagValueSuffixes(accountID, projectID, tr, nil, query, '.', 1, deadline) qHead = append(qHead, qTail...)
suffixes, err := s.SearchTagValueSuffixes(accountID, projectID, tr, nil, qHead, '.', 1, deadline)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1141,9 +1145,10 @@ func (s *Storage) SearchGraphitePaths(accountID, projectID uint32, tr TimeRange,
// The query matches a metric name with additional suffix. // The query matches a metric name with additional suffix.
return nil, nil return nil, nil
} }
return []string{queryStr}, nil return []string{string(qHead)}, nil
} }
suffixes, err := s.SearchTagValueSuffixes(accountID, projectID, tr, nil, query[:n], '.', maxPaths, deadline) qHead = append(qHead, qTail[:n]...)
suffixes, err := s.SearchTagValueSuffixes(accountID, projectID, tr, nil, qHead, '.', maxPaths, deadline)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1153,34 +1158,34 @@ func (s *Storage) SearchGraphitePaths(accountID, projectID uint32, tr TimeRange,
if len(suffixes) >= maxPaths { if len(suffixes) >= maxPaths {
return nil, fmt.Errorf("more than maxPaths=%d suffixes found", maxPaths) return nil, fmt.Errorf("more than maxPaths=%d suffixes found", maxPaths)
} }
qPrefixStr := queryStr[:n] qNode := qTail[n:]
qTail := "" qTail = nil
qNode := queryStr[n:]
mustMatchLeafs := true mustMatchLeafs := true
if m := strings.IndexByte(qNode, '.'); m >= 0 { if m := bytes.IndexByte(qNode, '.'); m >= 0 {
qTail = qNode[m+1:] qTail = qNode[m+1:]
qNode = qNode[:m+1] qNode = qNode[:m+1]
mustMatchLeafs = false mustMatchLeafs = false
} }
re, err := getRegexpForGraphiteQuery(qNode) re, err := getRegexpForGraphiteQuery(string(qNode))
if err != nil { if err != nil {
return nil, err return nil, err
} }
qHeadLen := len(qHead)
var paths []string var paths []string
for _, suffix := range suffixes { for _, suffix := range suffixes {
if len(paths) > maxPaths { if len(paths) > maxPaths {
paths = paths[:maxPaths] return nil, fmt.Errorf("more than maxPath=%d paths found", maxPaths)
break
} }
if !re.MatchString(suffix) { if !re.MatchString(suffix) {
continue continue
} }
if mustMatchLeafs { if mustMatchLeafs {
paths = append(paths, qPrefixStr+suffix) qHead = append(qHead[:qHeadLen], suffix...)
paths = append(paths, string(qHead))
continue continue
} }
q := qPrefixStr + suffix + qTail qHead = append(qHead[:qHeadLen], suffix...)
ps, err := s.SearchGraphitePaths(accountID, projectID, tr, []byte(q), maxPaths, deadline) ps, err := s.searchGraphitePaths(accountID, projectID, tr, qHead, qTail, maxPaths, deadline)
if err != nil { if err != nil {
return nil, err return nil, err
} }