diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2024-03-28 16:48:17 +0100 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2024-04-02 13:05:47 +0000 |
| commit | b5ad152b39d934d3fc79c2ccf261c4dc87571a54 (patch) | |
| tree | 05d49e862ee8dc68e1916b41c5e88a02c94e4dc0 /prog/mutation.go | |
| parent | 81b7a40ac5bab47ffe0b732c66522cfc922df3ad (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.go | 61 |
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) |
