diff options
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 +} |
