mirror of
https://github.com/prometheus/prometheus
synced 2026-04-20 22:41:05 +08:00
Merge pull request #18415 from roidelapluie/roidelapluie/proto-fuzz
fuzzing: add FuzzParseProtobuf fuzz target and corpus generation
This commit is contained in:
4
.github/workflows/fuzzing.yml
vendored
4
.github/workflows/fuzzing.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
fuzz_test: [FuzzParseMetricText, FuzzParseOpenMetric, FuzzParseMetricSelector, FuzzParseExpr, FuzzXORChunk, FuzzXOR2Chunk]
|
||||
fuzz_test: [FuzzParseMetricText, FuzzParseOpenMetric, FuzzParseMetricSelector, FuzzParseExpr, FuzzXORChunk, FuzzXOR2Chunk, FuzzParseProtobuf]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
with:
|
||||
go-version: 1.26.x
|
||||
- name: Run Fuzzing
|
||||
run: go test -fuzz=${{ matrix.fuzz_test }}$ -fuzztime=5m ./util/fuzzing
|
||||
run: go test -fuzz=${{ matrix.fuzz_test }}$ -fuzztime=4m ./util/fuzzing
|
||||
continue-on-error: true
|
||||
id: fuzz
|
||||
- name: Upload Crash Artifacts
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/prometheus/prometheus/util/fuzzing"
|
||||
)
|
||||
@@ -81,6 +82,16 @@ func run() error {
|
||||
}
|
||||
fmt.Printf("Generated fuzzXOR2Chunk_seed_corpus.zip with %d entries.\n", len(xor2Seeds))
|
||||
|
||||
// Generate FuzzParseProtobuf seed corpus.
|
||||
protobufSeeds, err := fuzzing.GetCorpusForFuzzParseProtobuf()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get corpus for FuzzParseProtobuf: %w", err)
|
||||
}
|
||||
if err := generateZipFromProtobufSeeds("fuzzParseProtobuf", protobufSeeds); err != nil {
|
||||
return fmt.Errorf("failed to generate fuzzParseProtobuf_seed_corpus.zip: %w", err)
|
||||
}
|
||||
fmt.Printf("Generated fuzzParseProtobuf_seed_corpus.zip with %d entries.\n", len(protobufSeeds))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -178,3 +189,19 @@ func generateZipFromXOR2ChunkSeeds(fuzzName string, seeds []fuzzing.XOR2ChunkFuz
|
||||
}
|
||||
return generateZipFromSeedEntries(fuzzName, entries)
|
||||
}
|
||||
|
||||
// generateZipFromProtobufSeeds creates a seed corpus ZIP file for FuzzParseProtobuf.
|
||||
func generateZipFromProtobufSeeds(fuzzName string, seeds []fuzzing.ProtobufCorpusSeed) error {
|
||||
entries := make([][]byte, len(seeds))
|
||||
for i, s := range seeds {
|
||||
entries[i] = []byte(fmt.Sprintf(
|
||||
"go test fuzz v1\n[]byte(%s)\nbool(%v)\nbool(%v)\nbool(%v)\nbool(%v)\n",
|
||||
strconv.Quote(string(s.Data)),
|
||||
s.IgnoreNative,
|
||||
s.ParseClassic,
|
||||
s.ConvertNHCB,
|
||||
s.TypeAndUnit,
|
||||
))
|
||||
}
|
||||
return generateZipFromSeedEntries(fuzzName, entries)
|
||||
}
|
||||
|
||||
1911
util/fuzzing/corpus_protobuf.go
Normal file
1911
util/fuzzing/corpus_protobuf.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@ import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/prometheus/model/exemplar"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/textparse"
|
||||
"github.com/prometheus/prometheus/model/value"
|
||||
@@ -284,6 +285,67 @@ func FuzzXOR2Chunk(f *testing.F) {
|
||||
})
|
||||
}
|
||||
|
||||
// FuzzParseProtobuf fuzzes the protobuf exposition-format parser. The four bool
|
||||
// parameters exercise different combinations of parser options:
|
||||
//
|
||||
// - ignoreNative: ignore native histogram parts of the payload
|
||||
// - parseClassic: also emit the classic representation when a native histogram is present
|
||||
// - convertNHCB: convert classic histograms to native histograms with custom buckets
|
||||
// - typeAndUnit: include type and unit labels on each series
|
||||
func FuzzParseProtobuf(f *testing.F) {
|
||||
corpus, err := GetCorpusForFuzzParseProtobuf()
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
}
|
||||
for _, s := range corpus {
|
||||
f.Add(s.Data, s.IgnoreNative, s.ParseClassic, s.ConvertNHCB, s.TypeAndUnit)
|
||||
}
|
||||
|
||||
f.Fuzz(func(t *testing.T, in []byte, ignoreNative, parseClassic, convertNHCB, typeAndUnit bool) {
|
||||
if len(in) > maxInputSize {
|
||||
t.Skip()
|
||||
}
|
||||
p := textparse.NewProtobufParser(in, ignoreNative, parseClassic, convertNHCB, typeAndUnit, symbolTable)
|
||||
var err error
|
||||
for {
|
||||
entry, nextErr := p.Next()
|
||||
err = nextErr
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
switch entry {
|
||||
case textparse.EntryHelp:
|
||||
_, _ = p.Help()
|
||||
case textparse.EntryType:
|
||||
_, _ = p.Type()
|
||||
case textparse.EntryUnit:
|
||||
_, _ = p.Unit()
|
||||
case textparse.EntrySeries:
|
||||
var lbs labels.Labels
|
||||
p.Labels(&lbs)
|
||||
_, _, _ = p.Series()
|
||||
_ = p.StartTimestamp()
|
||||
var ex exemplar.Exemplar
|
||||
for p.Exemplar(&ex) {
|
||||
}
|
||||
case textparse.EntryHistogram:
|
||||
var lbs labels.Labels
|
||||
p.Labels(&lbs)
|
||||
_, _, _, _ = p.Histogram()
|
||||
_ = p.StartTimestamp()
|
||||
var ex exemplar.Exemplar
|
||||
for p.Exemplar(&ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if errors.Is(err, io.EOF) {
|
||||
err = nil
|
||||
}
|
||||
// We don't care about errors, just that we don't panic.
|
||||
_ = err
|
||||
})
|
||||
}
|
||||
|
||||
// FuzzParseExpr fuzzes the expression parser.
|
||||
func FuzzParseExpr(f *testing.F) {
|
||||
// Add seed corpus from built-in test expressions
|
||||
|
||||
Reference in New Issue
Block a user