diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2020-11-20 17:30:23 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-11-21 08:46:20 +0100 |
| commit | 5405d2e2ed019de7452677eacfc7de9562a8ea12 (patch) | |
| tree | 7b2f9f488a4b57ce9a40e4d16bc263c2f00d8e48 /pkg/ifuzz/ifuzz.go | |
| parent | 9bc78a846441516a33a7fd3b245380f463ba88ed (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/ifuzz.go')
| -rw-r--r-- | pkg/ifuzz/ifuzz.go | 160 |
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 +} |
