Skip to content

Commit

Permalink
prog: use optimized mutation parameters
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
a-nogikh committed Apr 2, 2024
1 parent 81b7a40 commit b5ad152
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 9 deletions.
61 changes: 52 additions & 9 deletions prog/mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions prog/mutation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ func TestMutateArgument(t *testing.T) {
ncalls: 2 * len(p.Calls),
ct: ct,
corpus: nil,
opts: DefaultMutateOpts,
}
ctx.mutateArg()
data1 := p1.Serialize()
Expand Down Expand Up @@ -179,6 +180,7 @@ func TestSizeMutateArg(t *testing.T) {
ncalls: 2 * len(p.Calls),
ct: ct,
corpus: nil,
opts: DefaultMutateOpts,
}
ctx.mutateArg()
ForeachArg(p.Calls[0], func(arg Arg, ctx *ArgCtx) {
Expand Down

0 comments on commit b5ad152

Please sign in to comment.