aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/ifuzz/ifuzzimpl/ifuzzimpl.go')
-rw-r--r--pkg/ifuzz/ifuzzimpl/ifuzzimpl.go145
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
+}