aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/corpus/corpus.go20
-rw-r--r--pkg/cover/canonicalizer.go38
-rw-r--r--pkg/cover/canonicalizer_test.go46
-rw-r--r--pkg/fuzzer/cover.go6
-rw-r--r--pkg/fuzzer/fuzzer.go77
-rw-r--r--pkg/fuzzer/fuzzer_test.go7
-rw-r--r--pkg/fuzzer/job.go29
-rw-r--r--pkg/fuzzer/stats.go26
-rw-r--r--pkg/rpctype/rpctype.go72
-rw-r--r--pkg/signal/signal.go71
10 files changed, 165 insertions, 227 deletions
diff --git a/pkg/corpus/corpus.go b/pkg/corpus/corpus.go
index 772037178..8eed1fc63 100644
--- a/pkg/corpus/corpus.go
+++ b/pkg/corpus/corpus.go
@@ -9,7 +9,6 @@ import (
"github.com/google/syzkaller/pkg/cover"
"github.com/google/syzkaller/pkg/hash"
- "github.com/google/syzkaller/pkg/rpctype"
"github.com/google/syzkaller/pkg/signal"
"github.com/google/syzkaller/prog"
)
@@ -63,15 +62,6 @@ func (item Item) StringCall() string {
return stringCall(item.Prog, item.Call)
}
-// RPCInputShort() does not include coverage.
-func (item Item) RPCInputShort() rpctype.Input {
- return rpctype.Input{
- Call: item.Call,
- Prog: item.ProgData,
- Signal: item.Signal.Serialize(),
- }
-}
-
func stringCall(p *prog.Prog, call int) string {
if call != -1 {
return p.Calls[call].Meta.Name
@@ -91,16 +81,6 @@ func (item NewInput) StringCall() string {
return stringCall(item.Prog, item.Call)
}
-func (item NewInput) RPCInput() rpctype.Input {
- return rpctype.Input{
- Call: item.Call,
- Prog: item.Prog.Serialize(),
- Signal: item.Signal.Serialize(),
- Cover: item.Cover,
- RawCover: item.RawCover,
- }
-}
-
type NewItemEvent struct {
Sig string
Exists bool
diff --git a/pkg/cover/canonicalizer.go b/pkg/cover/canonicalizer.go
index c7c385aed..d3b014af8 100644
--- a/pkg/cover/canonicalizer.go
+++ b/pkg/cover/canonicalizer.go
@@ -9,7 +9,6 @@ import (
"github.com/google/syzkaller/pkg/host"
"github.com/google/syzkaller/pkg/log"
- "github.com/google/syzkaller/pkg/signal"
)
type Canonicalizer struct {
@@ -120,18 +119,18 @@ func (can *Canonicalizer) NewInstance(modules []host.KernelModule) *Canonicalize
}
}
-func (ci *CanonicalizerInstance) Canonicalize(cov []uint32, sign signal.Serial) ([]uint32, signal.Serial) {
+func (ci *CanonicalizerInstance) Canonicalize(elems []uint32) []uint32 {
if ci.canonical.moduleKeys == nil {
- return cov, sign
+ return elems
}
- return ci.canonicalize.convertPCs(cov, sign)
+ return ci.canonicalize.convertPCs(elems)
}
-func (ci *CanonicalizerInstance) Decanonicalize(cov []uint32, sign signal.Serial) ([]uint32, signal.Serial) {
+func (ci *CanonicalizerInstance) Decanonicalize(elems []uint32) []uint32 {
if ci.canonical.moduleKeys == nil {
- return cov, sign
+ return elems
}
- return ci.decanonicalize.convertPCs(cov, sign)
+ return ci.decanonicalize.convertPCs(elems)
}
func (ci *CanonicalizerInstance) DecanonicalizeFilter(bitmap map[uint32]uint32) map[uint32]uint32 {
@@ -177,34 +176,21 @@ func findModule(pc uint32, moduleKeys []uint32) (moduleIdx int) {
return moduleIdx - 1
}
-func (convert *Convert) convertPCs(cov []uint32, sign signal.Serial) ([]uint32, signal.Serial) {
+func (convert *Convert) convertPCs(pcs []uint32) []uint32 {
// Convert coverage.
- var retCov []uint32
+ var ret []uint32
convCtx := &convertContext{convert: convert}
- for _, pc := range cov {
+ for _, pc := range pcs {
if newPC, ok := convert.convertPC(pc); ok {
- retCov = append(retCov, newPC)
+ ret = append(ret, newPC)
} else {
convCtx.discard(pc)
}
}
if msg := convCtx.discarded(); msg != "" {
- log.Logf(4, "error in PC conversion: %v", msg)
- }
- // Convert signals.
- retSign := &signal.Serial{}
- convCtx = &convertContext{convert: convert}
- for idx, elem := range sign.Elems {
- if newSign, ok := convert.convertPC(uint32(elem)); ok {
- retSign.AddElem(newSign, sign.Prios[idx])
- } else {
- convCtx.discard(uint32(elem))
- }
- }
- if msg := convCtx.discarded(); msg != "" {
- log.Logf(4, "error in signal conversion: %v", msg)
+ log.Logf(4, "error in PC/signal conversion: %v", msg)
}
- return retCov, *retSign
+ return ret
}
func (convert *Convert) convertPC(pc uint32) (uint32, bool) {
diff --git a/pkg/cover/canonicalizer_test.go b/pkg/cover/canonicalizer_test.go
index db418abe1..aa840a96f 100644
--- a/pkg/cover/canonicalizer_test.go
+++ b/pkg/cover/canonicalizer_test.go
@@ -13,7 +13,6 @@ import (
"github.com/google/syzkaller/pkg/cover"
"github.com/google/syzkaller/pkg/host"
- "github.com/google/syzkaller/pkg/signal"
)
type RPCServer struct {
@@ -28,8 +27,8 @@ type Fuzzer struct {
goalCov []uint32
bitmap map[uint32]uint32
goalBitmap map[uint32]uint32
- sign signal.Serial
- goalSign signal.Serial
+ sign []uint32
+ goalSign []uint32
}
type canonicalizeValue int
@@ -49,13 +48,9 @@ func TestNilModules(t *testing.T) {
serv.fuzzers["f1"].cov = []uint32{0x00010000, 0x00020000, 0x00030000, 0x00040000}
serv.fuzzers["f1"].goalCov = []uint32{0x00010000, 0x00020000, 0x00030000, 0x00040000}
- serv.fuzzers["f1"].sign = signal.FromRaw(serv.fuzzers["f1"].cov, 0).Serialize()
- serv.fuzzers["f1"].goalSign = signal.FromRaw(serv.fuzzers["f1"].goalCov, 0).Serialize()
serv.fuzzers["f2"].cov = []uint32{0x00010000, 0x00020000, 0x00030000, 0x00040000}
serv.fuzzers["f2"].goalCov = []uint32{0x00010000, 0x00020000, 0x00030000, 0x00040000}
- serv.fuzzers["f2"].sign = signal.FromRaw(serv.fuzzers["f2"].cov, 0).Serialize()
- serv.fuzzers["f2"].goalSign = signal.FromRaw(serv.fuzzers["f2"].goalCov, 0).Serialize()
serv.fuzzers["f1"].bitmap = map[uint32]uint32{
0x00010011: 1,
@@ -87,15 +82,15 @@ func TestNilModules(t *testing.T) {
}
serv.fuzzers["f1"].goalCov = []uint32{0x00010000, 0x00020000, 0x00030000, 0x00040000}
- serv.fuzzers["f1"].goalSign = signal.FromRaw(serv.fuzzers["f1"].goalCov, 0).Serialize()
+ serv.fuzzers["f1"].goalSign = serv.fuzzers["f1"].goalCov
serv.fuzzers["f2"].goalCov = []uint32{0x00010000, 0x00020000, 0x00030000, 0x00040000}
- serv.fuzzers["f2"].goalSign = signal.FromRaw(serv.fuzzers["f2"].goalCov, 0).Serialize()
+ serv.fuzzers["f2"].goalSign = serv.fuzzers["f2"].goalCov
if err := serv.runTest(Decanonicalize); err != "" {
t.Fatalf("failed in decanonicalization: %v", err)
}
}
-// Confirms there is no change to signals if coverage is disabled and fallback signals are used.
+// Confirms there is no change to PCs if coverage is disabled and fallback signals are used.
func TestDisabledSignals(t *testing.T) {
serv := &RPCServer{
fuzzers: make(map[string]*Fuzzer),
@@ -112,18 +107,18 @@ func TestDisabledSignals(t *testing.T) {
serv.connect("f2", f2Modules, false)
pcs := []uint32{0x00010000, 0x00020000, 0x00030000, 0x00040000}
- serv.fuzzers["f1"].sign = signal.FromRaw(pcs, 0).Serialize()
- serv.fuzzers["f1"].goalSign = signal.FromRaw(pcs, 0).Serialize()
+ serv.fuzzers["f1"].cov = pcs
+ serv.fuzzers["f1"].goalCov = pcs
- serv.fuzzers["f2"].sign = signal.FromRaw(pcs, 0).Serialize()
- serv.fuzzers["f2"].goalSign = signal.FromRaw(pcs, 0).Serialize()
+ serv.fuzzers["f2"].sign = pcs
+ serv.fuzzers["f2"].goalSign = pcs
if err := serv.runTest(Canonicalize); err != "" {
t.Fatalf("failed in canonicalization: %v", err)
}
- serv.fuzzers["f1"].goalSign = signal.FromRaw(pcs, 0).Serialize()
- serv.fuzzers["f2"].goalSign = signal.FromRaw(pcs, 0).Serialize()
+ serv.fuzzers["f1"].goalSign = pcs
+ serv.fuzzers["f2"].goalSign = pcs
if err := serv.runTest(Decanonicalize); err != "" {
t.Fatalf("failed in decanonicalization: %v", err)
}
@@ -152,8 +147,6 @@ func TestModules(t *testing.T) {
0x00035000, 0x00040000, 0x00045000, 0x00050000, 0x00055000}
serv.fuzzers["f1"].goalCov = []uint32{0x00010000, 0x00015000, 0x00020000, 0x00025000, 0x00030000,
0x00035000, 0x00040000, 0x00045000, 0x00050000, 0x00055000}
- serv.fuzzers["f1"].sign = signal.FromRaw(serv.fuzzers["f1"].cov, 0).Serialize()
- serv.fuzzers["f1"].goalSign = signal.FromRaw(serv.fuzzers["f1"].goalCov, 0).Serialize()
// The modules addresss are inverted between: (2 and 4), (3 and 5),
// affecting the output canonical coverage values in these ranges.
@@ -161,8 +154,6 @@ func TestModules(t *testing.T) {
0x00035000, 0x00040000, 0x00045000, 0x00050000, 0x00055000}
serv.fuzzers["f2"].goalCov = []uint32{0x00010000, 0x00015000, 0x00040000, 0x00025000, 0x00045000,
0x0004a000, 0x00020000, 0x00030000, 0x0003b000, 0x00055000}
- serv.fuzzers["f2"].sign = signal.FromRaw(serv.fuzzers["f2"].cov, 0).Serialize()
- serv.fuzzers["f2"].goalSign = signal.FromRaw(serv.fuzzers["f2"].goalCov, 0).Serialize()
serv.fuzzers["f1"].bitmap = map[uint32]uint32{
0x00010011: 1,
@@ -195,10 +186,8 @@ func TestModules(t *testing.T) {
serv.fuzzers["f1"].goalCov = []uint32{0x00010000, 0x00015000, 0x00020000, 0x00025000, 0x00030000,
0x00035000, 0x00040000, 0x00045000, 0x00050000, 0x00055000}
- serv.fuzzers["f1"].goalSign = signal.FromRaw(serv.fuzzers["f1"].goalCov, 0).Serialize()
serv.fuzzers["f2"].goalCov = []uint32{0x00010000, 0x00015000, 0x00020000, 0x00025000, 0x00030000,
0x00035000, 0x00040000, 0x00045000, 0x00050000, 0x00055000}
- serv.fuzzers["f2"].goalSign = signal.FromRaw(serv.fuzzers["f2"].goalCov, 0).Serialize()
if err := serv.runTest(Decanonicalize); err != "" {
t.Fatalf("failed in decanonicalization: %v", err)
}
@@ -225,15 +214,12 @@ func TestChangingModules(t *testing.T) {
// in this range should be deleted.
serv.fuzzers["f2"].cov = []uint32{0x00010000, 0x00015000, 0x00020000, 0x00025000}
serv.fuzzers["f2"].goalCov = []uint32{0x00010000, 0x00015000, 0x00025000}
- serv.fuzzers["f2"].sign = signal.FromRaw(serv.fuzzers["f2"].cov, 0).Serialize()
- serv.fuzzers["f2"].goalSign = signal.FromRaw(serv.fuzzers["f2"].goalCov, 0).Serialize()
if err := serv.runTest(Canonicalize); err != "" {
t.Fatalf("failed in canonicalization: %v", err)
}
serv.fuzzers["f2"].goalCov = []uint32{0x00010000, 0x00015000, 0x00025000}
- serv.fuzzers["f2"].goalSign = signal.FromRaw(serv.fuzzers["f2"].goalCov, 0).Serialize()
if err := serv.runTest(Decanonicalize); err != "" {
t.Fatalf("failed in decanonicalization: %v", err)
}
@@ -241,12 +227,11 @@ func TestChangingModules(t *testing.T) {
func (serv *RPCServer) runTest(val canonicalizeValue) string {
var cov []uint32
- var sign signal.Serial
for name, fuzzer := range serv.fuzzers {
if val == Canonicalize {
- cov, sign = fuzzer.instModules.Canonicalize(fuzzer.cov, fuzzer.sign)
+ cov = fuzzer.instModules.Canonicalize(fuzzer.cov)
} else {
- cov, sign = fuzzer.instModules.Decanonicalize(fuzzer.cov, fuzzer.sign)
+ cov = fuzzer.instModules.Decanonicalize(fuzzer.cov)
instBitmap := fuzzer.instModules.DecanonicalizeFilter(fuzzer.bitmap)
if !reflect.DeepEqual(instBitmap, fuzzer.goalBitmap) {
return fmt.Sprintf("failed in bitmap conversion. Fuzzer %v.\nExpected: 0x%x.\nReturned: 0x%x",
@@ -257,12 +242,7 @@ func (serv *RPCServer) runTest(val canonicalizeValue) string {
return fmt.Sprintf("failed in coverage conversion. Fuzzer %v.\nExpected: 0x%x.\nReturned: 0x%x",
name, fuzzer.goalCov, cov)
}
- if !reflect.DeepEqual(sign.Deserialize(), fuzzer.goalSign.Deserialize()) {
- return fmt.Sprintf("failed in signal conversion. Fuzzer %v.\nExpected: 0x%x.\nReturned: 0x%x",
- name, fuzzer.goalSign, sign)
- }
fuzzer.cov = cov
- fuzzer.sign = sign
}
return ""
}
diff --git a/pkg/fuzzer/cover.go b/pkg/fuzzer/cover.go
index 886da004d..5af00f167 100644
--- a/pkg/fuzzer/cover.go
+++ b/pkg/fuzzer/cover.go
@@ -35,6 +35,12 @@ func (cover *Cover) addRawMaxSignal(signal []uint32, prio uint8) signal.Signal {
return diff
}
+func (cover *Cover) CopyMaxSignal() signal.Signal {
+ cover.mu.RLock()
+ defer cover.mu.RUnlock()
+ return cover.maxSignal.Copy()
+}
+
func (cover *Cover) GrabNewSignal() signal.Signal {
cover.mu.Lock()
defer cover.mu.Unlock()
diff --git a/pkg/fuzzer/fuzzer.go b/pkg/fuzzer/fuzzer.go
index 196e59506..14c3f5902 100644
--- a/pkg/fuzzer/fuzzer.go
+++ b/pkg/fuzzer/fuzzer.go
@@ -13,15 +13,15 @@ import (
"time"
"github.com/google/syzkaller/pkg/corpus"
- "github.com/google/syzkaller/pkg/hash"
"github.com/google/syzkaller/pkg/ipc"
+ "github.com/google/syzkaller/pkg/rpctype"
+ "github.com/google/syzkaller/pkg/signal"
"github.com/google/syzkaller/prog"
)
type Fuzzer struct {
- Config *Config
- Cover *Cover
- NeedCandidates chan struct{}
+ Config *Config
+ Cover *Cover
ctx context.Context
mu sync.Mutex
@@ -39,18 +39,16 @@ type Fuzzer struct {
runningJobs atomic.Int64
queuedCandidates atomic.Int64
- // If the source of candidates runs out of them, we risk
- // generating too many needCandidate requests (one for
- // each Config.MinCandidates). We prevent this with candidatesRequested.
- candidatesRequested atomic.Bool
+
+ outOfQueue atomic.Bool
+ outOfQueueNext atomic.Int64
}
func NewFuzzer(ctx context.Context, cfg *Config, rnd *rand.Rand,
target *prog.Target) *Fuzzer {
f := &Fuzzer{
- Config: cfg,
- Cover: &Cover{},
- NeedCandidates: make(chan struct{}, 1),
+ Config: cfg,
+ Cover: &Cover{},
ctx: ctx,
stats: map[string]uint64{},
@@ -82,18 +80,16 @@ type Config struct {
EnabledCalls map[*prog.Syscall]bool
NoMutateCalls map[int]bool
FetchRawCover bool
- // If the number of queued candidates is less than MinCandidates,
- // NeedCandidates is triggered.
- MinCandidates uint
- NewInputs chan corpus.NewInput
+ NewInputFilter func(input *corpus.NewInput) bool
}
type Request struct {
Prog *prog.Prog
NeedCover bool
NeedRawCover bool
- NeedSignal bool
+ NeedSignal rpctype.SignalType
NeedHints bool
+ SignalFilter signal.Signal // If specified, the resulting signal MAY be a subset of it.
// Fields that are only relevant within pkg/fuzzer.
flags ProgTypes
stat string
@@ -110,7 +106,7 @@ func (fuzzer *Fuzzer) Done(req *Request, res *Result) {
// Triage individual calls.
// We do it before unblocking the waiting threads because
// it may result it concurrent modification of req.Prog.
- if req.NeedSignal && res.Info != nil {
+ if req.NeedSignal != rpctype.NoSignal && res.Info != nil {
for call, info := range res.Info.Calls {
fuzzer.triageProgCall(req.Prog, &info, call, req.flags)
}
@@ -166,7 +162,6 @@ func signalPrio(p *prog.Prog, info *ipc.CallInfo, call int) (prio uint8) {
type Candidate struct {
Prog *prog.Prog
- Hash hash.Sig
Smashed bool
Minimized bool
}
@@ -178,20 +173,19 @@ func (fuzzer *Fuzzer) NextInput() *Request {
panic("queuedCandidates is out of sync")
}
}
- if fuzzer.NeedCandidatesNow() &&
- !fuzzer.candidatesRequested.CompareAndSwap(false, true) {
- select {
- case fuzzer.NeedCandidates <- struct{}{}:
- default:
- }
- }
return req
}
func (fuzzer *Fuzzer) nextInput() *Request {
- nextExec := fuzzer.nextExec.tryPop()
- if nextExec != nil {
- return nextExec.value
+ // The fuzzer may get biased to one specific part of the kernel.
+ // Periodically generate random programs to ensure that the coverage
+ // is more uniform.
+ if !fuzzer.outOfQueue.Load() ||
+ fuzzer.outOfQueueNext.Add(1)%400 > 0 {
+ nextExec := fuzzer.nextExec.tryPop()
+ if nextExec != nil {
+ return nextExec.value
+ }
}
// Either generate a new input or mutate an existing one.
mutateRate := 0.95
@@ -227,16 +221,15 @@ func (fuzzer *Fuzzer) Logf(level int, msg string, args ...interface{}) {
fuzzer.Config.Logf(level, msg, args...)
}
-func (fuzzer *Fuzzer) NeedCandidatesNow() bool {
- return fuzzer.queuedCandidates.Load() < int64(fuzzer.Config.MinCandidates)
-}
-
func (fuzzer *Fuzzer) AddCandidates(candidates []Candidate) {
fuzzer.queuedCandidates.Add(int64(len(candidates)))
for _, candidate := range candidates {
fuzzer.pushExec(candidateRequest(candidate), priority{candidatePrio})
}
- fuzzer.candidatesRequested.Store(false)
+}
+
+func (fuzzer *Fuzzer) EnableOutOfQueue() {
+ fuzzer.outOfQueue.Store(true)
}
func (fuzzer *Fuzzer) rand() *rand.Rand {
@@ -250,7 +243,7 @@ func (fuzzer *Fuzzer) pushExec(req *Request, prio priority) {
if req.stat == "" {
panic("Request.Stat field must be set")
}
- if req.NeedHints && (req.NeedCover || req.NeedSignal) {
+ if req.NeedHints && (req.NeedCover || req.NeedSignal != rpctype.NoSignal) {
panic("Request.NeedHints is mutually exclusive with other fields")
}
fuzzer.nextExec.push(&priorityQueueItem[*Request]{
@@ -330,19 +323,3 @@ func (fuzzer *Fuzzer) logCurrentStats() {
fuzzer.Logf(0, "%s", str)
}
}
-
-type Stats struct {
- CoverStats
- corpus.Stats
- Candidates int
- RunningJobs int
-}
-
-func (fuzzer *Fuzzer) Stats() Stats {
- return Stats{
- CoverStats: fuzzer.Cover.Stats(),
- Stats: fuzzer.Config.Corpus.Stats(),
- Candidates: int(fuzzer.queuedCandidates.Load()),
- RunningJobs: int(fuzzer.runningJobs.Load()),
- }
-}
diff --git a/pkg/fuzzer/fuzzer_test.go b/pkg/fuzzer/fuzzer_test.go
index 4f8cf41c5..bd6d9a8fe 100644
--- a/pkg/fuzzer/fuzzer_test.go
+++ b/pkg/fuzzer/fuzzer_test.go
@@ -22,6 +22,7 @@ import (
"github.com/google/syzkaller/pkg/csource"
"github.com/google/syzkaller/pkg/ipc"
"github.com/google/syzkaller/pkg/ipc/ipcconfig"
+ "github.com/google/syzkaller/pkg/rpctype"
"github.com/google/syzkaller/pkg/testutil"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys/targets"
@@ -54,7 +55,6 @@ func TestFuzz(t *testing.T) {
EnabledCalls: map[*prog.Syscall]bool{
target.SyscallMap["syz_test_fuzzer1"]: true,
},
- NewInputs: make(chan corpus.NewInput),
}, rand.New(testutil.RandSource(t)), target)
go func() {
@@ -129,7 +129,7 @@ func emulateExec(req *Request) (*Result, string, error) {
if req.NeedCover {
callInfo.Cover = []uint32{cover}
}
- if req.NeedSignal {
+ if req.NeedSignal != rpctype.NoSignal {
callInfo.Signal = []uint32{cover}
}
info.Calls = append(info.Calls, callInfo)
@@ -205,7 +205,6 @@ func (f *testFuzzer) wait() {
for title, cnt := range f.crashes {
t.Logf("%s: %d", title, cnt)
}
- t.Logf("stats:\n%v", f.fuzzer.GrabStats())
}
// TODO: it's already implemented in syz-fuzzer/proc.go,
@@ -239,7 +238,7 @@ var crashRe = regexp.MustCompile(`{{CRASH: (.*?)}}`)
func (proc *executorProc) execute(req *Request) (*Result, string, error) {
execOpts := proc.execOpts
// TODO: it's duplicated from fuzzer.go.
- if req.NeedSignal {
+ if req.NeedSignal != rpctype.NoSignal {
execOpts.Flags |= ipc.FlagCollectSignal
}
if req.NeedCover {
diff --git a/pkg/fuzzer/job.go b/pkg/fuzzer/job.go
index dfc0b807e..f567fc2cc 100644
--- a/pkg/fuzzer/job.go
+++ b/pkg/fuzzer/job.go
@@ -10,6 +10,7 @@ import (
"github.com/google/syzkaller/pkg/corpus"
"github.com/google/syzkaller/pkg/cover"
"github.com/google/syzkaller/pkg/ipc"
+ "github.com/google/syzkaller/pkg/rpctype"
"github.com/google/syzkaller/pkg/signal"
"github.com/google/syzkaller/prog"
)
@@ -64,7 +65,7 @@ func genProgRequest(fuzzer *Fuzzer, rnd *rand.Rand) *Request {
fuzzer.ChoiceTable())
return &Request{
Prog: p,
- NeedSignal: true,
+ NeedSignal: rpctype.NewSignal,
stat: statGenerate,
}
}
@@ -83,7 +84,7 @@ func mutateProgRequest(fuzzer *Fuzzer, rnd *rand.Rand) *Request {
)
return &Request{
Prog: newP,
- NeedSignal: true,
+ NeedSignal: rpctype.NewSignal,
stat: statFuzz,
}
}
@@ -98,7 +99,7 @@ func candidateRequest(input Candidate) *Request {
}
return &Request{
Prog: input.Prog,
- NeedSignal: true,
+ NeedSignal: rpctype.NewSignal,
stat: statCandidate,
flags: flags,
}
@@ -157,13 +158,10 @@ func (job *triageJob) run(fuzzer *Fuzzer) {
Cover: info.cover.Serialize(),
RawCover: info.rawCover,
}
- fuzzer.Config.Corpus.Save(input)
- if fuzzer.Config.NewInputs != nil {
- select {
- case <-fuzzer.ctx.Done():
- case fuzzer.Config.NewInputs <- input:
- }
+ if filter := fuzzer.Config.NewInputFilter; filter != nil && !filter(&input) {
+ return
}
+ fuzzer.Config.Corpus.Save(input)
}
type deflakedCover struct {
@@ -179,7 +177,7 @@ func (job *triageJob) deflake(fuzzer *Fuzzer) (info deflakedCover, stop bool) {
for i := 0; i < signalRuns; i++ {
result := fuzzer.exec(job, &Request{
Prog: job.p,
- NeedSignal: true,
+ NeedSignal: rpctype.AllSignal,
NeedCover: true,
NeedRawCover: fuzzer.Config.FetchRawCover,
stat: statTriage,
@@ -226,9 +224,10 @@ func (job *triageJob) minimize(fuzzer *Fuzzer, newSignal signal.Signal) (stop bo
}
for i := 0; i < minimizeAttempts; i++ {
result := fuzzer.exec(job, &Request{
- Prog: p1,
- NeedSignal: true,
- stat: statMinimize,
+ Prog: p1,
+ NeedSignal: rpctype.AllSignal,
+ SignalFilter: newSignal,
+ stat: statMinimize,
})
if result.Stop {
stop = true
@@ -298,7 +297,7 @@ func (job *smashJob) run(fuzzer *Fuzzer) {
fuzzer.Config.Corpus.Programs())
result := fuzzer.exec(job, &Request{
Prog: p,
- NeedSignal: true,
+ NeedSignal: rpctype.NewSignal,
stat: statSmash,
})
if result.Stop {
@@ -386,7 +385,7 @@ func (job *hintsJob) run(fuzzer *Fuzzer) {
func(p *prog.Prog) bool {
result := fuzzer.exec(job, &Request{
Prog: p,
- NeedSignal: true,
+ NeedSignal: rpctype.NewSignal,
stat: statHint,
})
return !result.Stop
diff --git a/pkg/fuzzer/stats.go b/pkg/fuzzer/stats.go
index 17bc6131c..044febc64 100644
--- a/pkg/fuzzer/stats.go
+++ b/pkg/fuzzer/stats.go
@@ -3,6 +3,8 @@
package fuzzer
+import "github.com/google/syzkaller/pkg/corpus"
+
const (
statGenerate = "exec gen"
statFuzz = "exec fuzz"
@@ -17,10 +19,28 @@ const (
statBufferTooSmall = "buffer too small"
)
-func (fuzzer *Fuzzer) GrabStats() map[string]uint64 {
+type Stats struct {
+ CoverStats
+ corpus.Stats
+ Candidates int
+ RunningJobs int
+ // Let's keep stats in Named as long as the rest of the code does not depend
+ // on their specific values.
+ Named map[string]uint64
+}
+
+func (fuzzer *Fuzzer) Stats() Stats {
+ ret := Stats{
+ CoverStats: fuzzer.Cover.Stats(),
+ Stats: fuzzer.Config.Corpus.Stats(),
+ Candidates: int(fuzzer.queuedCandidates.Load()),
+ RunningJobs: int(fuzzer.runningJobs.Load()),
+ Named: make(map[string]uint64),
+ }
fuzzer.mu.Lock()
defer fuzzer.mu.Unlock()
- ret := fuzzer.stats
- fuzzer.stats = map[string]uint64{}
+ for k, v := range fuzzer.stats {
+ ret.Named[k] = v
+ }
return ret
}
diff --git a/pkg/rpctype/rpctype.go b/pkg/rpctype/rpctype.go
index efd9d6589..9f0b6846e 100644
--- a/pkg/rpctype/rpctype.go
+++ b/pkg/rpctype/rpctype.go
@@ -13,20 +13,47 @@ import (
"github.com/google/syzkaller/pkg/signal"
)
-type Input struct {
- Call int // seq number of call in the prog to which the item is related (-1 for extra)
- Prog []byte
- Signal signal.Serial
- Cover []uint32
- RawCover []uint32
+type SignalType int
+
+const (
+ NoSignal SignalType = 0 // we don't need any signal
+ NewSignal SignalType = 1 // we need the newly seen signal
+ AllSignal SignalType = 2 // we need all signal
+)
+
+// ExecutionRequest describes the task of executing a particular program.
+// Corresponds to Fuzzer.Request.
+type ExecutionRequest struct {
+ ID int64
+ ProgData []byte
+ NeedCover bool
+ NeedRawCover bool
+ NeedHints bool
+ NeedSignal SignalType
+ SignalFilter signal.Signal
+}
+
+// ExecutionResult is sent after ExecutionRequest is completed.
+type ExecutionResult struct {
+ ID int64
+ Info ipc.ProgInfo
+}
+
+// ExchangeInfoRequest is periodically sent by syz-fuzzer to syz-manager.
+type ExchangeInfoRequest struct {
+ Name string
+ NeedProgs int
+ StatsDelta map[string]uint64
+ Results []ExecutionResult
}
-type Candidate struct {
- Prog []byte
- Minimized bool
- Smashed bool
+// ExchangeInfoReply is a reply to ExchangeInfoRequest.
+type ExchangeInfoReply struct {
+ Requests []ExecutionRequest
+ NewMaxSignal []uint32
}
+// TODO: merge ExecutionRequest and ExecTask.
type ExecTask struct {
Prog []byte
ID int64
@@ -40,7 +67,6 @@ type ConnectArgs struct {
type ConnectRes struct {
EnabledCalls []int
- NoMutateCalls map[int]bool
GitRevision string
TargetRevision string
AllSandboxes bool
@@ -64,24 +90,6 @@ type SyscallReason struct {
Reason string
}
-type NewInputArgs struct {
- Name string
- Input
-}
-
-type PollArgs struct {
- Name string
- NeedCandidates bool
- MaxSignal signal.Serial
- Stats map[string]uint64
-}
-
-type PollRes struct {
- Candidates []Candidate
- NewInputs []Input
- MaxSignal signal.Serial
-}
-
type RunnerConnectArgs struct {
Pool, VM int
}
@@ -199,9 +207,3 @@ type RunTestDoneArgs struct {
Info []*ipc.ProgInfo
Error string
}
-
-type LogMessageReq struct {
- Level int
- Name string
- Message string
-}
diff --git a/pkg/signal/signal.go b/pkg/signal/signal.go
index 7a2a8bd16..2860be95e 100644
--- a/pkg/signal/signal.go
+++ b/pkg/signal/signal.go
@@ -11,11 +11,6 @@ type (
type Signal map[elemType]prioType
-type Serial struct {
- Elems []elemType
- Prios []prioType
-}
-
func (s Signal) Len() int {
return len(s)
}
@@ -64,42 +59,6 @@ func FromRaw(raw []uint32, prio uint8) Signal {
return s
}
-func (s Signal) Serialize() Serial {
- if s.Empty() {
- return Serial{}
- }
- res := Serial{
- Elems: make([]elemType, len(s)),
- Prios: make([]prioType, len(s)),
- }
- i := 0
- for e, p := range s {
- res.Elems[i] = e
- res.Prios[i] = p
- i++
- }
- return res
-}
-
-func (ser *Serial) AddElem(elem uint32, prio prioType) {
- ser.Elems = append(ser.Elems, elemType(elem))
- ser.Prios = append(ser.Prios, prio)
-}
-
-func (ser Serial) Deserialize() Signal {
- if len(ser.Elems) != len(ser.Prios) {
- panic("corrupted Serial")
- }
- if len(ser.Elems) == 0 {
- return nil
- }
- s := make(Signal, len(ser.Elems))
- for i, e := range ser.Elems {
- s[e] = ser.Prios[i]
- }
- return s
-}
-
func (s Signal) Diff(s1 Signal) Signal {
if s1.Empty() {
return nil
@@ -160,6 +119,36 @@ func (s *Signal) Merge(s1 Signal) {
}
}
+// FilterRaw returns a subset of original raw elements that coincides with the one in Signal.
+func (s Signal) FilterRaw(raw []uint32) []uint32 {
+ var ret []uint32
+ for _, e := range raw {
+ if _, ok := s[elemType(e)]; ok {
+ ret = append(ret, e)
+ }
+ }
+ return ret
+}
+
+// DiffFromRaw returns a subset of the raw elements that is not present in Signal.
+func (s Signal) DiffFromRaw(raw []uint32) []uint32 {
+ var ret []uint32
+ for _, e := range raw {
+ if _, ok := s[elemType(e)]; !ok {
+ ret = append(ret, e)
+ }
+ }
+ return ret
+}
+
+func (s Signal) ToRaw() []uint32 {
+ var raw []uint32
+ for e := range s {
+ raw = append(raw, uint32(e))
+ }
+ return raw
+}
+
type Context struct {
Signal Signal
Context interface{}