aboutsummaryrefslogtreecommitdiffstats
path: root/prog/mutation.go
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2024-03-28 16:48:17 +0100
committerAleksandr Nogikh <nogikh@google.com>2024-04-02 13:05:47 +0000
commitb5ad152b39d934d3fc79c2ccf261c4dc87571a54 (patch)
tree05d49e862ee8dc68e1916b41c5e88a02c94e4dc0 /prog/mutation.go
parent81b7a40ac5bab47ffe0b732c66522cfc922df3ad (diff)
prog: use optimized mutation parameters
These parameters have been selected by a local experiment. On syz-testbed, they seem to help syzkaller find +15% more different crash types per single run and +30% more crash types overall. Later we might want to choose these parameters during the actual run.
Diffstat (limited to 'prog/mutation.go')
-rw-r--r--prog/mutation.go61
1 files changed, 52 insertions, 9 deletions
diff --git a/prog/mutation.go b/prog/mutation.go
index 54f88c175..8547be3cc 100644
--- a/prog/mutation.go
+++ b/prog/mutation.go
@@ -25,6 +25,37 @@ const maxBlobLen = uint64(100 << 10)
// noMutate: Set of IDs of syscalls which should not be mutated.
// corpus: The entire corpus, including original program p.
func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, noMutate map[int]bool, corpus []*Prog) {
+ p.MutateWithOpts(rs, ncalls, ct, noMutate, corpus, DefaultMutateOpts)
+}
+
+var DefaultMutateOpts = MutateOpts{
+ ExpectedIterations: 5,
+ MutateArgCount: 3,
+
+ SquashWeight: 50,
+ SpliceWeight: 200,
+ InsertWeight: 100,
+ MutateArgWeight: 100,
+ RemoveCallWeight: 10,
+}
+
+type MutateOpts struct {
+ ExpectedIterations int
+ MutateArgCount int
+ SquashWeight int
+ SpliceWeight int
+ InsertWeight int
+ MutateArgWeight int
+ RemoveCallWeight int
+}
+
+func (o MutateOpts) weight() int {
+ return o.SquashWeight + o.SpliceWeight + o.InsertWeight + o.MutateArgWeight + o.RemoveCallWeight
+}
+
+func (p *Prog) MutateWithOpts(rs rand.Source, ncalls int, ct *ChoiceTable, noMutate map[int]bool,
+ corpus []*Prog, opts MutateOpts) {
+ totalWeight := opts.weight()
r := newRand(p.Target, rs)
if ncalls < len(p.Calls) {
ncalls = len(p.Calls)
@@ -36,22 +67,33 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, noMutate map[
ct: ct,
noMutate: noMutate,
corpus: corpus,
+ opts: opts,
}
- for stop, ok := false, false; !stop; stop = ok && len(p.Calls) != 0 && r.oneOf(3) {
- switch {
- case r.oneOf(5):
+ for stop, ok := false, false; !stop; stop = ok && len(p.Calls) != 0 && r.oneOf(opts.ExpectedIterations) {
+ val := r.Intn(totalWeight)
+ val -= opts.SquashWeight
+ if val < 0 {
// Not all calls have anything squashable,
// so this has lower priority in reality.
ok = ctx.squashAny()
- case r.nOutOf(1, 100):
+ continue
+ }
+ val -= opts.SpliceWeight
+ if val < 0 {
ok = ctx.splice()
- case r.nOutOf(20, 31):
+ continue
+ }
+ val -= opts.InsertWeight
+ if val < 0 {
ok = ctx.insertCall()
- case r.nOutOf(10, 11):
+ continue
+ }
+ val -= opts.MutateArgWeight
+ if val < 0 {
ok = ctx.mutateArg()
- default:
- ok = ctx.removeCall()
+ continue
}
+ ok = ctx.removeCall()
}
p.sanitizeFix()
p.debugValidate()
@@ -69,6 +111,7 @@ type mutator struct {
ct *ChoiceTable // ChoiceTable for syscalls.
noMutate map[int]bool // Set of IDs of syscalls which should not be mutated.
corpus []*Prog // The entire corpus, including original program p.
+ opts MutateOpts
}
// This function selects a random other program p0 out of the corpus, and
@@ -184,7 +227,7 @@ func (ctx *mutator) mutateArg() bool {
return false
}
updateSizes := true
- for stop, ok := false, false; !stop; stop = ok && r.oneOf(3) {
+ for stop, ok := false, false; !stop; stop = ok && r.oneOf(ctx.opts.MutateArgCount) {
ok = true
ma := &mutationArgs{target: p.Target}
ForeachArg(c, ma.collectArg)