// Copyright 2017 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. package prog import ( "fmt" "math/rand" "sort" ) // Target describes target OS/arch pair. type Target struct { OS string Arch string Revision string // unique hash representing revision of the descriptions PtrSize uint64 PageSize uint64 DataOffset uint64 Syscalls []*Syscall Resources []*ResourceDesc Structs []*KeyedStruct Consts []ConstValue // Syscall used by MakeMmap. // It has some special meaning because there are usually too many of them. MmapSyscall *Syscall // MakeMmap creates call that maps [start, start+npages) page range. MakeMmap func(start, npages uint64) *Call // AnalyzeMmap analyzes the call c regarding mapping/unmapping memory. // If it maps/unmaps any memory returns [start, start+npages) range, // otherwise returns npages = 0. AnalyzeMmap func(c *Call) (start, npages uint64, mapped bool) // SanitizeCall neutralizes harmful calls. SanitizeCall func(c *Call) // SpecialStructs allows target to do custom generation/mutation for some struct types. // Map key is struct name for which custom generation/mutation is required. // Map value is custom generation/mutation function that will be called // for the corresponding structs. g is helper object that allows generate random numbers, // allocate memory, etc. typ is the struct type. old is the old value of the struct // for mutation, or nil for generation. The function returns a new value of the struct, // and optionally any calls that need to be inserted before the arg reference. SpecialStructs map[string]func(g *Gen, typ *StructType, old *GroupArg) (Arg, []*Call) // Special strings that can matter for the target. // Used as fallback when string type does not have own dictionary. StringDictionary []string // Filled by prog package: SyscallMap map[string]*Syscall ConstMap map[string]uint64 resourceMap map[string]*ResourceDesc // Maps resource name to a list of calls that can create the resource. resourceCtors map[string][]*Syscall } var targets = make(map[string]*Target) func RegisterTarget(target *Target, initArch func(target *Target)) { key := target.OS + "/" + target.Arch if targets[key] != nil { panic(fmt.Sprintf("duplicate target %v", key)) } target.SanitizeCall = func(c *Call) {} initTarget(target) initArch(target) target.ConstMap = nil // currently used only by initArch targets[key] = target } func GetTarget(OS, arch string) (*Target, error) { key := OS + "/" + arch target := targets[key] if target == nil { var supported []string for _, t := range targets { supported = append(supported, fmt.Sprintf("%v/%v", t.OS, t.Arch)) } sort.Strings(supported) return nil, fmt.Errorf("unknown target: %v (supported: %v)", key, supported) } return target, nil } func AllTargets() []*Target { var res []*Target for _, t := range targets { res = append(res, t) } sort.Slice(res, func(i, j int) bool { if res[i].OS != res[j].OS { return res[i].OS < res[j].OS } return res[i].Arch < res[j].Arch }) return res } func initTarget(target *Target) { target.ConstMap = make(map[string]uint64) for _, c := range target.Consts { target.ConstMap[c.Name] = c.Value } target.resourceMap = make(map[string]*ResourceDesc) for _, res := range target.Resources { target.resourceMap[res.Name] = res } keyedStructs := make(map[StructKey]*StructDesc) for _, desc := range target.Structs { keyedStructs[desc.Key] = desc.Desc } target.Structs = nil target.SyscallMap = make(map[string]*Syscall) for _, c := range target.Syscalls { target.SyscallMap[c.Name] = c ForeachType(c, func(t0 Type) { switch t := t0.(type) { case *ResourceType: t.Desc = target.resourceMap[t.TypeName] if t.Desc == nil { panic("no resource desc") } case *StructType: t.StructDesc = keyedStructs[t.Key] if t.StructDesc == nil { panic("no struct desc") } case *UnionType: t.StructDesc = keyedStructs[t.Key] if t.StructDesc == nil { panic("no union desc") } } }) } target.resourceCtors = make(map[string][]*Syscall) for _, res := range target.Resources { target.resourceCtors[res.Name] = target.calcResourceCtors(res.Kind, false) } } type Gen struct { r *randGen s *state } func (g *Gen) Rand() *rand.Rand { return g.r.Rand } func (g *Gen) NOutOf(n, outOf int) bool { return g.r.nOutOf(n, outOf) } func (g *Gen) Alloc(ptrType Type, data Arg) (Arg, []*Call) { return g.r.addr(g.s, ptrType, data.Size(), data) } func (g *Gen) GenerateArg(typ Type, pcalls *[]*Call) Arg { arg, calls := g.r.generateArg(g.s, typ) *pcalls = append(*pcalls, calls...) return arg }