aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ifuzz/ifuzz.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/ifuzz/ifuzz.go')
-rw-r--r--pkg/ifuzz/ifuzz.go160
1 files changed, 119 insertions, 41 deletions
diff --git a/pkg/ifuzz/ifuzz.go b/pkg/ifuzz/ifuzz.go
index 4b51b30f3..45082834d 100644
--- a/pkg/ifuzz/ifuzz.go
+++ b/pkg/ifuzz/ifuzz.go
@@ -5,56 +5,134 @@ package ifuzz
import (
"math/rand"
-)
-const (
- ModeLong64 = iota
- ModeProt32
- ModeProt16
- ModeReal16
- ModeLast
+ "github.com/google/syzkaller/pkg/ifuzz/ifuzzimpl"
+ _ "github.com/google/syzkaller/pkg/ifuzz/powerpc/generated" // pull in generated instruction descriptions
+ _ "github.com/google/syzkaller/pkg/ifuzz/x86/generated" // pull in generated instruction descriptions
)
-type Config struct {
- Arch string
- Len int // number of instructions to generate
- Mode int // 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
-}
-
-type MemRegion struct {
- Start uint64
- Size uint64
-}
+type (
+ Config = ifuzzimpl.Config
+ MemRegion = ifuzzimpl.MemRegion
+ Mode = ifuzzimpl.Mode
+)
const (
- TypeExec = iota
- TypePriv
- TypeUser
- TypeAll
- TypeLast
+ ArchX86 = ifuzzimpl.ArchX86
+ ArchPowerPC = ifuzzimpl.ArchPowerPC
+ ModeLong64 = ifuzzimpl.ModeLong64
+ ModeProt32 = ifuzzimpl.ModeProt32
+ ModeProt16 = ifuzzimpl.ModeProt16
+ ModeReal16 = ifuzzimpl.ModeReal16
)
-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 *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, insntype int) []Insn
- Decode(mode int, text []byte) (int, error)
- DecodeExt(mode int, text []byte) (int, error) // XED, to keep ifuzz_test happy
+func Mutate(cfg *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
}
-const (
- ArchX86 = "x86"
- ArchPowerPC = "powerpc"
-)
+func randInsn(cfg *Config, r *rand.Rand) ifuzzimpl.Insn {
+ insnset := ifuzzimpl.Arches[cfg.Arch]
+ var insns []ifuzzimpl.Insn
+ if cfg.Priv && cfg.Exec {
+ insns = insnset.GetInsns(cfg.Mode, ifuzzimpl.Type(r.Intn(3)))
+ } else if cfg.Priv {
+ insns = insnset.GetInsns(cfg.Mode, ifuzzimpl.Type(r.Intn(2)))
+ } else {
+ insns = insnset.GetInsns(cfg.Mode, ifuzzimpl.TypeUser)
+ }
+ return insns[r.Intn(len(insns))]
+}
-var SpecialNumbers = [...]uint64{0, 1 << 15, 1 << 16, 1 << 31, 1 << 32, 1 << 47, 1 << 47, 1 << 63}
+func split(cfg *Config, text []byte) [][]byte {
+ insnset := ifuzzimpl.Arches[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
+}