aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ifuzz/ifuzzimpl
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-11-20 17:30:23 +0100
committerDmitry Vyukov <dvyukov@google.com>2020-11-21 08:46:20 +0100
commit5405d2e2ed019de7452677eacfc7de9562a8ea12 (patch)
tree7b2f9f488a4b57ce9a40e4d16bc263c2f00d8e48 /pkg/ifuzz/ifuzzimpl
parent9bc78a846441516a33a7fd3b245380f463ba88ed (diff)
pkg/ifuzz: invert ifuzz and ifuzzimpl
ifuzzimpl imports the public interface package ifuzz and prog package needs to import ifuzzimpl (implementation guts that nobody outside of ifuzz should care about). This is not right. Invert everything so that prog package only needs to import ifuzz and ifuzz imports ifuzzimpl.
Diffstat (limited to 'pkg/ifuzz/ifuzzimpl')
-rw-r--r--pkg/ifuzz/ifuzzimpl/ifuzzimpl.go180
1 files changed, 59 insertions, 121 deletions
diff --git a/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go b/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go
index f1ea64f37..71485172c 100644
--- a/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go
+++ b/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go
@@ -4,142 +4,80 @@
package ifuzzimpl
import (
- "github.com/google/syzkaller/pkg/ifuzz"
"math/rand"
)
-var (
- Types = make(map[string]ifuzz.InsnSet)
+const (
+ ArchX86 = "x86"
+ ArchPowerPC = "powerpc"
)
-func Register(arch string, insns ifuzz.InsnSet) {
- Types[arch] = insns
-}
+var Arches = make(map[string]InsnSet)
-// 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
+type (
+ Mode int
+ Type int
+)
+
+type Insn interface {
+ GetName() string
+ GetMode() int
+ GetPseudo() bool
+ GetPriv() bool
+ IsCompatible(cfg *Config) bool
+ Encode(cfg *Config, r *rand.Rand) []byte
}
-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
+type InsnSet interface {
+ GetInsns(mode Mode, typ Type) []Insn
+ Decode(mode Mode, text []byte) (int, error)
+ DecodeExt(mode Mode, text []byte) (int, error) // XED, to keep ifuzz_test happy
}
-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
+type Config struct {
+ Arch string
+ Len int // number of instructions to generate
+ Mode Mode // one of ModeXXX
+ Priv bool // generate CPL=0 instructions (x86), HV/!PR mode (PPC)
+ Exec bool // generate instructions sequences interesting for execution
+ MemRegions []MemRegion // generated instructions will reference these regions
}
-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))]
+type MemRegion struct {
+ Start uint64
+ Size uint64
}
-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:]
+const (
+ ModeLong64 Mode = iota
+ ModeProt32
+ ModeProt16
+ ModeReal16
+ ModeLast
+)
+
+const (
+ TypeExec Type = iota
+ TypePriv
+ TypeUser
+ TypeAll
+ TypeLast
+)
+
+// ModeInsns returns list of all instructions for the given mode.
+func ModeInsns(cfg *Config) []Insn {
+ insnset := Arches[cfg.Arch]
+ if cfg.Mode < 0 || cfg.Mode >= ModeLast {
+ panic("bad mode")
}
- if bad != nil {
- insns = append(insns, bad)
+ insns := insnset.GetInsns(cfg.Mode, TypeUser)
+ if cfg.Priv {
+ insns = append(insns, insnset.GetInsns(cfg.Mode, TypePriv)...)
+ if cfg.Exec {
+ insns = append(insns, insnset.GetInsns(cfg.Mode, TypeExec)...)
+ }
}
return insns
}
+
+var SpecialNumbers = [...]uint64{0, 1 << 15, 1 << 16, 1 << 31, 1 << 32, 1 << 47, 1 << 47, 1 << 63}