aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ifuzz/ifuzzimpl
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@linux.ibm.com>2020-09-02 18:11:22 +1000
committerDmitry Vyukov <dvyukov@google.com>2020-11-20 15:31:42 +0100
commite72f8f11e096d36aefc41a35c718dced97c45dea (patch)
tree6619d0089d8ac172c64853c76c0b1acc9485d192 /pkg/ifuzz/ifuzzimpl
parent740ff4615a9ced4a8a016365aa44674b9b0e807d (diff)
pkg/ifuzz: reorganize files to allow other architectures
At the moment ifuzz only generates x86 instructions. In order to support instruction fuzzing for others (ARM, POWERPC), some separation of the common and arch layers is needed. This adds 2 packages: 1. "x86" where x86 instruction generator goes to 2. "ifuzzimpl which contains some common code. The goal was to keep changes to the rand.go to the minimum. The next patch will use this when adding PPC64. This should cause no behavioural change. Signed-off-by: Alexey Kardashevskiy <aik@linux.ibm.com>
Diffstat (limited to 'pkg/ifuzz/ifuzzimpl')
-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
+}