diff options
Diffstat (limited to 'pkg/ifuzz/ifuzzimpl/ifuzzimpl.go')
| -rw-r--r-- | pkg/ifuzz/ifuzzimpl/ifuzzimpl.go | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go b/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go new file mode 100644 index 000000000..f1ea64f37 --- /dev/null +++ b/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go @@ -0,0 +1,145 @@ +// Copyright 2017 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package ifuzzimpl + +import ( + "github.com/google/syzkaller/pkg/ifuzz" + "math/rand" +) + +var ( + Types = make(map[string]ifuzz.InsnSet) +) + +func Register(arch string, insns ifuzz.InsnSet) { + Types[arch] = insns +} + +// ModeInsns returns list of all instructions for the given mode. +func ModeInsns(cfg *ifuzz.Config) []ifuzz.Insn { + insnset := Types[cfg.Arch] + if cfg.Mode < 0 || cfg.Mode >= ifuzz.ModeLast { + panic("bad mode") + } + var insns []ifuzz.Insn + insns = append(insns, insnset.GetInsns(cfg.Mode, ifuzz.TypeUser)...) + if cfg.Priv { + insns = append(insns, insnset.GetInsns(cfg.Mode, ifuzz.TypePriv)...) + if cfg.Exec { + insns = append(insns, insnset.GetInsns(cfg.Mode, ifuzz.TypeExec)...) + } + } + return insns +} + +func Generate(cfg *ifuzz.Config, r *rand.Rand) []byte { + var text []byte + for i := 0; i < cfg.Len; i++ { + insn := randInsn(cfg, r) + text = append(text, insn.Encode(cfg, r)...) + } + return text +} + +func Mutate(cfg *ifuzz.Config, r *rand.Rand, text []byte) []byte { + insns := split(cfg, text) + retry := false + for stop := false; !stop || retry || len(insns) == 0; stop = r.Intn(2) == 0 { + retry = false + switch x := r.Intn(100); { + case x < 10 && len(insns) != 0: + // Delete instruction. + i := r.Intn(len(insns)) + copy(insns[i:], insns[i+1:]) + insns = insns[:len(insns)-1] + case x < 40 && len(insns) != 0: + // Replace instruction with another. + insn := randInsn(cfg, r) + text1 := insn.Encode(cfg, r) + i := r.Intn(len(insns)) + insns[i] = text1 + case x < 70 && len(insns) != 0: + // Mutate instruction. + i := r.Intn(len(insns)) + text1 := insns[i] + for stop := false; !stop || len(text1) == 0; stop = r.Intn(2) == 0 { + switch x := r.Intn(100); { + case x < 5 && len(text1) != 0: + // Delete byte. + pos := r.Intn(len(text1)) + copy(text1[pos:], text1[pos+1:]) + text1 = text1[:len(text1)-1] + case x < 40 && len(text1) != 0: + // Replace a byte. + pos := r.Intn(len(text1)) + text1[pos] = byte(r.Intn(256)) + case x < 70 && len(text1) != 0: + // Flip a bit. + pos := r.Intn(len(text1)) + text1[pos] ^= 1 << byte(r.Intn(8)) + default: + // Insert a byte. + pos := r.Intn(len(text1) + 1) + text1 = append(text1, 0) + copy(text1[pos+1:], text1[pos:]) + text1[pos] = byte(r.Intn(256)) + } + } + insns[i] = text1 + case len(insns) < cfg.Len: + // Insert a new instruction. + insn := randInsn(cfg, r) + text1 := insn.Encode(cfg, r) + i := r.Intn(len(insns) + 1) + insns = append(insns, nil) + copy(insns[i+1:], insns[i:]) + insns[i] = text1 + default: + retry = true + } + } + text = nil + for _, insn := range insns { + text = append(text, insn...) + } + return text +} + +func randInsn(cfg *ifuzz.Config, r *rand.Rand) ifuzz.Insn { + insnset := Types[cfg.Arch] + var insns []ifuzz.Insn + if cfg.Priv && cfg.Exec { + insns = insnset.GetInsns(cfg.Mode, r.Intn(3)) + } else if cfg.Priv { + insns = insnset.GetInsns(cfg.Mode, r.Intn(2)) + } else { + insns = insnset.GetInsns(cfg.Mode, ifuzz.TypeUser) + } + return insns[r.Intn(len(insns))] +} + +func split(cfg *ifuzz.Config, text []byte) [][]byte { + insnset := Types[cfg.Arch] + text = append([]byte{}, text...) + var insns [][]byte + var bad []byte + for len(text) != 0 { + n, err := insnset.Decode(cfg.Mode, text) + if err != nil || n == 0 { + bad = append(bad, text[0]) + text = text[1:] + continue + } + if bad != nil { + insns = append(insns, bad) + bad = nil + } + insns = append(insns, text[:n]) + text = text[n:] + } + if bad != nil { + insns = append(insns, bad) + } + return insns +} |
