From 5405d2e2ed019de7452677eacfc7de9562a8ea12 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 20 Nov 2020 17:30:23 +0100 Subject: 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. --- pkg/ifuzz/ifuzz.go | 160 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 41 deletions(-) (limited to 'pkg/ifuzz/ifuzz.go') 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 +} -- cgit mrf-deployment