From 2addfcda6297288cd48c399dfbef1f5752162011 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 29 May 2024 11:28:03 +0200 Subject: syz-manager: add corpus triage mode Add corpus triage mode and support it in testbed. This is useful to benchmark just the triage phase w/o any subsequent fuzzing. First, fuzzing is more random. Second, if triage duration is different in different versions, then they will do different amount of fuzzing in fixed testbed time. --- pkg/fuzzer/fuzzer.go | 16 ++++++++++++---- pkg/fuzzer/queue/queue.go | 11 ----------- pkg/fuzzer/queue/queue_test.go | 12 +----------- pkg/fuzzer/stats.go | 43 ++++++++++++++++++++++-------------------- 4 files changed, 36 insertions(+), 46 deletions(-) (limited to 'pkg') diff --git a/pkg/fuzzer/fuzzer.go b/pkg/fuzzer/fuzzer.go index 9ad218433..8be912139 100644 --- a/pkg/fuzzer/fuzzer.go +++ b/pkg/fuzzer/fuzzer.go @@ -76,7 +76,7 @@ type execQueues struct { func newExecQueues(fuzzer *Fuzzer) execQueues { ret := execQueues{ triageCandidateQueue: queue.DynamicOrder(), - candidateQueue: queue.PlainWithStat(fuzzer.StatCandidates), + candidateQueue: queue.Plain(), triageQueue: queue.DynamicOrder(), smashQueue: queue.Plain(), } @@ -92,6 +92,10 @@ func newExecQueues(fuzzer *Fuzzer) execQueues { return ret } +func (fuzzer *Fuzzer) CandidateTriageFinished() bool { + return fuzzer.statCandidates.Val()+fuzzer.statJobsTriageCandidate.Val() == 0 +} + func (fuzzer *Fuzzer) execute(executor queue.Executor, req *queue.Request) *queue.Result { return fuzzer.executeWithFlags(executor, req, 0) } @@ -130,6 +134,9 @@ func (fuzzer *Fuzzer) processResult(req *queue.Request, res *queue.Result, flags if res.Info != nil { fuzzer.statExecTime.Add(int(res.Info.Elapsed / 1e6)) } + if flags&progCandidate != 0 { + fuzzer.statCandidates.Add(-1) + } } type Config struct { @@ -161,11 +168,11 @@ func (fuzzer *Fuzzer) triageProgCall(p *prog.Prog, info *flatrpc.CallInfo, call } fuzzer.Logf(2, "found new signal in call %d in %s", call, p) - queue := fuzzer.triageQueue + queue, stat := fuzzer.triageQueue, fuzzer.statJobsTriage if flags&progCandidate > 0 { - queue = fuzzer.triageCandidateQueue + queue, stat = fuzzer.triageCandidateQueue, fuzzer.statJobsTriageCandidate } - fuzzer.startJob(fuzzer.statJobsTriage, &triageJob{ + fuzzer.startJob(stat, &triageJob{ p: p.Clone(), call: call, info: info, @@ -243,6 +250,7 @@ type Candidate struct { } func (fuzzer *Fuzzer) AddCandidates(candidates []Candidate) { + fuzzer.statCandidates.Add(len(candidates)) for _, candidate := range candidates { req, flags := candidateRequest(fuzzer, candidate) fuzzer.enqueue(fuzzer.candidateQueue, req, flags) diff --git a/pkg/fuzzer/queue/queue.go b/pkg/fuzzer/queue/queue.go index a9411c1bd..cb70f5a9b 100644 --- a/pkg/fuzzer/queue/queue.go +++ b/pkg/fuzzer/queue/queue.go @@ -173,7 +173,6 @@ type Source interface { // PlainQueue is a straighforward thread-safe Request queue implementation. type PlainQueue struct { - stat *stats.Val mu sync.Mutex queue []*Request pos int @@ -183,10 +182,6 @@ func Plain() *PlainQueue { return &PlainQueue{} } -func PlainWithStat(val *stats.Val) *PlainQueue { - return &PlainQueue{stat: val} -} - func (pq *PlainQueue) Len() int { pq.mu.Lock() defer pq.mu.Unlock() @@ -194,9 +189,6 @@ func (pq *PlainQueue) Len() int { } func (pq *PlainQueue) Submit(req *Request) { - if pq.stat != nil { - pq.stat.Add(1) - } pq.mu.Lock() defer pq.mu.Unlock() @@ -235,9 +227,6 @@ func (pq *PlainQueue) nextLocked() *Request { ret := pq.queue[pq.pos] pq.queue[pq.pos] = nil pq.pos++ - if pq.stat != nil { - pq.stat.Add(-1) - } return ret } diff --git a/pkg/fuzzer/queue/queue_test.go b/pkg/fuzzer/queue/queue_test.go index a89ec0d3d..5b6a03ed0 100644 --- a/pkg/fuzzer/queue/queue_test.go +++ b/pkg/fuzzer/queue/queue_test.go @@ -6,29 +6,19 @@ package queue import ( "testing" - "github.com/google/syzkaller/pkg/stats" "github.com/stretchr/testify/assert" ) func TestPlainQueue(t *testing.T) { - val := stats.Create("v0", "desc0") - pq := PlainWithStat(val) + pq := Plain() req1, req2, req3 := &Request{}, &Request{}, &Request{} pq.Submit(req1) - assert.Equal(t, 1, val.Val()) pq.Submit(req2) - assert.Equal(t, 2, val.Val()) - assert.Equal(t, req1, pq.Next()) - assert.Equal(t, 1, val.Val()) - assert.Equal(t, req2, pq.Next()) - assert.Equal(t, 0, val.Val()) - pq.Submit(req3) - assert.Equal(t, 1, val.Val()) assert.Equal(t, req3, pq.Next()) assert.Nil(t, pq.Next()) } diff --git a/pkg/fuzzer/stats.go b/pkg/fuzzer/stats.go index c860b8bb9..2129c048a 100644 --- a/pkg/fuzzer/stats.go +++ b/pkg/fuzzer/stats.go @@ -6,35 +6,38 @@ package fuzzer import "github.com/google/syzkaller/pkg/stats" type Stats struct { - StatCandidates *stats.Val - statNewInputs *stats.Val - statJobs *stats.Val - statJobsTriage *stats.Val - statJobsSmash *stats.Val - statJobsHints *stats.Val - statExecTime *stats.Val - statExecGenerate *stats.Val - statExecFuzz *stats.Val - statExecCandidate *stats.Val - statExecTriage *stats.Val - statExecMinimize *stats.Val - statExecSmash *stats.Val - statExecHint *stats.Val - statExecSeed *stats.Val - statExecCollide *stats.Val + statCandidates *stats.Val + statNewInputs *stats.Val + statJobs *stats.Val + statJobsTriage *stats.Val + statJobsTriageCandidate *stats.Val + statJobsSmash *stats.Val + statJobsHints *stats.Val + statExecTime *stats.Val + statExecGenerate *stats.Val + statExecFuzz *stats.Val + statExecCandidate *stats.Val + statExecTriage *stats.Val + statExecMinimize *stats.Val + statExecSmash *stats.Val + statExecHint *stats.Val + statExecSeed *stats.Val + statExecCollide *stats.Val } func newStats() Stats { return Stats{ - StatCandidates: stats.Create("candidates", "Number of candidate programs in triage queue", + statCandidates: stats.Create("candidates", "Number of candidate programs in triage queue", stats.Console, stats.Graph("corpus")), statNewInputs: stats.Create("new inputs", "Potential untriaged corpus candidates", stats.Graph("corpus")), statJobs: stats.Create("fuzzer jobs", "Total running fuzzer jobs", stats.NoGraph), statJobsTriage: stats.Create("triage jobs", "Running triage jobs", stats.StackedGraph("jobs")), - statJobsSmash: stats.Create("smash jobs", "Running smash jobs", stats.StackedGraph("jobs")), - statJobsHints: stats.Create("hints jobs", "Running hints jobs", stats.StackedGraph("jobs")), - statExecTime: stats.Create("prog exec time", "Test program execution time (ms)", stats.Distribution{}), + statJobsTriageCandidate: stats.Create("candidate triage jobs", "Running candidate triage jobs", + stats.StackedGraph("jobs")), + statJobsSmash: stats.Create("smash jobs", "Running smash jobs", stats.StackedGraph("jobs")), + statJobsHints: stats.Create("hints jobs", "Running hints jobs", stats.StackedGraph("jobs")), + statExecTime: stats.Create("prog exec time", "Test program execution time (ms)", stats.Distribution{}), statExecGenerate: stats.Create("exec gen", "Executions of generated programs", stats.Rate{}, stats.StackedGraph("exec")), statExecFuzz: stats.Create("exec fuzz", "Executions of mutated programs", -- cgit mrf-deployment