2017-09-05 11:31:14 +00:00
|
|
|
// 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"
|
2017-11-22 10:42:10 +00:00
|
|
|
"math/rand"
|
2017-09-14 19:27:56 +00:00
|
|
|
"sort"
|
2017-12-13 10:58:10 +00:00
|
|
|
"sync"
|
2017-09-05 11:31:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Target describes target OS/arch pair.
|
|
|
|
type Target struct {
|
|
|
|
OS string
|
|
|
|
Arch string
|
2017-09-15 08:15:00 +00:00
|
|
|
Revision string // unique hash representing revision of the descriptions
|
2017-09-05 11:31:14 +00:00
|
|
|
PtrSize uint64
|
|
|
|
PageSize uint64
|
|
|
|
DataOffset uint64
|
|
|
|
|
|
|
|
Syscalls []*Syscall
|
|
|
|
Resources []*ResourceDesc
|
2017-09-20 19:18:36 +00:00
|
|
|
Structs []*KeyedStruct
|
|
|
|
Consts []ConstValue
|
2017-09-05 11:31:14 +00:00
|
|
|
|
2017-09-14 08:32:29 +00:00
|
|
|
// Syscall used by MakeMmap.
|
|
|
|
// It has some special meaning because there are usually too many of them.
|
|
|
|
MmapSyscall *Syscall
|
|
|
|
|
2017-09-05 11:31:14 +00:00
|
|
|
// 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)
|
|
|
|
|
2018-01-24 18:28:36 +00:00
|
|
|
// SpecialTypes allows target to do custom generation/mutation for some struct's and union's.
|
|
|
|
// Map key is struct/union name for which custom generation/mutation is required.
|
2017-09-05 11:31:14 +00:00
|
|
|
// Map value is custom generation/mutation function that will be called
|
2018-01-24 18:28:36 +00:00
|
|
|
// for the corresponding type. g is helper object that allows generate random numbers,
|
|
|
|
// allocate memory, etc. typ is the struct/union type. old is the old value of the struct/union
|
|
|
|
// for mutation, or nil for generation. The function returns a new value of the struct/union,
|
2017-09-05 11:31:14 +00:00
|
|
|
// and optionally any calls that need to be inserted before the arg reference.
|
2018-01-24 18:28:36 +00:00
|
|
|
SpecialTypes map[string]func(g *Gen, typ Type, old Arg) (Arg, []*Call)
|
2017-09-05 11:31:14 +00:00
|
|
|
|
2017-09-05 14:28:58 +00:00
|
|
|
// Special strings that can matter for the target.
|
|
|
|
// Used as fallback when string type does not have own dictionary.
|
|
|
|
StringDictionary []string
|
|
|
|
|
2017-09-14 17:25:01 +00:00
|
|
|
// Filled by prog package:
|
2017-12-13 10:58:10 +00:00
|
|
|
init sync.Once
|
|
|
|
initArch func(target *Target)
|
2017-09-14 17:25:01 +00:00
|
|
|
SyscallMap map[string]*Syscall
|
2017-09-20 19:18:36 +00:00
|
|
|
ConstMap map[string]uint64
|
2017-09-05 14:32:32 +00:00
|
|
|
resourceMap map[string]*ResourceDesc
|
|
|
|
// Maps resource name to a list of calls that can create the resource.
|
2017-09-05 11:31:14 +00:00
|
|
|
resourceCtors map[string][]*Syscall
|
|
|
|
}
|
|
|
|
|
|
|
|
var targets = make(map[string]*Target)
|
|
|
|
|
2017-09-20 19:18:36 +00:00
|
|
|
func RegisterTarget(target *Target, initArch func(target *Target)) {
|
2017-09-05 11:31:14 +00:00
|
|
|
key := target.OS + "/" + target.Arch
|
|
|
|
if targets[key] != nil {
|
|
|
|
panic(fmt.Sprintf("duplicate target %v", key))
|
|
|
|
}
|
2017-12-13 10:58:10 +00:00
|
|
|
target.initArch = initArch
|
2017-09-05 11:31:14 +00:00
|
|
|
targets[key] = target
|
2017-09-13 13:15:36 +00:00
|
|
|
}
|
2017-09-05 11:31:14 +00:00
|
|
|
|
2017-09-14 17:25:01 +00:00
|
|
|
func GetTarget(OS, arch string) (*Target, error) {
|
2017-09-13 13:15:36 +00:00
|
|
|
key := OS + "/" + arch
|
|
|
|
target := targets[key]
|
|
|
|
if target == nil {
|
2017-09-13 18:40:27 +00:00
|
|
|
var supported []string
|
|
|
|
for _, t := range targets {
|
|
|
|
supported = append(supported, fmt.Sprintf("%v/%v", t.OS, t.Arch))
|
|
|
|
}
|
2017-09-14 19:27:56 +00:00
|
|
|
sort.Strings(supported)
|
2017-09-14 17:25:01 +00:00
|
|
|
return nil, fmt.Errorf("unknown target: %v (supported: %v)", key, supported)
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
2017-12-13 10:58:10 +00:00
|
|
|
target.init.Do(target.lazyInit)
|
2017-09-14 17:25:01 +00:00
|
|
|
return target, nil
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 19:27:56 +00:00
|
|
|
func AllTargets() []*Target {
|
|
|
|
var res []*Target
|
2017-12-13 10:58:10 +00:00
|
|
|
for _, target := range targets {
|
|
|
|
target.init.Do(target.lazyInit)
|
|
|
|
res = append(res, target)
|
2017-09-14 19:27:56 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-12-13 10:58:10 +00:00
|
|
|
func (target *Target) lazyInit() {
|
|
|
|
target.SanitizeCall = func(c *Call) {}
|
|
|
|
target.initTarget()
|
|
|
|
target.initArch(target)
|
|
|
|
target.ConstMap = nil // currently used only by initArch
|
|
|
|
}
|
|
|
|
|
|
|
|
func (target *Target) initTarget() {
|
2017-09-20 19:18:36 +00:00
|
|
|
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
|
|
|
|
|
2017-09-14 17:25:01 +00:00
|
|
|
target.SyscallMap = make(map[string]*Syscall)
|
2017-09-05 11:31:14 +00:00
|
|
|
for _, c := range target.Syscalls {
|
2017-09-14 17:25:01 +00:00
|
|
|
target.SyscallMap[c.Name] = c
|
2017-09-20 19:18:36 +00:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
2017-09-20 19:18:36 +00:00
|
|
|
|
2017-09-05 11:31:14 +00:00
|
|
|
target.resourceCtors = make(map[string][]*Syscall)
|
2017-09-20 19:18:36 +00:00
|
|
|
for _, res := range target.Resources {
|
|
|
|
target.resourceCtors[res.Name] = target.calcResourceCtors(res.Kind, false)
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Gen struct {
|
|
|
|
r *randGen
|
|
|
|
s *state
|
|
|
|
}
|
|
|
|
|
2018-02-17 16:17:56 +00:00
|
|
|
func (g *Gen) Target() *Target {
|
|
|
|
return g.r.target
|
|
|
|
}
|
|
|
|
|
2017-11-22 10:42:10 +00:00
|
|
|
func (g *Gen) Rand() *rand.Rand {
|
|
|
|
return g.r.Rand
|
|
|
|
}
|
|
|
|
|
2017-09-05 11:31:14 +00:00
|
|
|
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)
|
|
|
|
}
|
2017-11-22 10:42:10 +00:00
|
|
|
|
|
|
|
func (g *Gen) GenerateArg(typ Type, pcalls *[]*Call) Arg {
|
2018-01-24 18:28:36 +00:00
|
|
|
return g.generateArg(typ, pcalls, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *Gen) GenerateSpecialArg(typ Type, pcalls *[]*Call) Arg {
|
|
|
|
return g.generateArg(typ, pcalls, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *Gen) generateArg(typ Type, pcalls *[]*Call, ignoreSpecial bool) Arg {
|
|
|
|
arg, calls := g.r.generateArgImpl(g.s, typ, ignoreSpecial)
|
2017-11-22 10:42:10 +00:00
|
|
|
*pcalls = append(*pcalls, calls...)
|
2018-01-24 18:28:36 +00:00
|
|
|
g.r.target.assignSizesArray([]Arg{arg})
|
2017-11-22 10:42:10 +00:00
|
|
|
return arg
|
|
|
|
}
|
2018-01-24 18:28:36 +00:00
|
|
|
|
|
|
|
func (g *Gen) MutateArg(arg0 Arg) (calls []*Call) {
|
|
|
|
updateSizes := true
|
|
|
|
for stop := false; !stop; stop = g.r.oneOf(3) {
|
|
|
|
args, bases, parents := g.r.target.mutationSubargs(arg0)
|
|
|
|
if len(args) == 0 {
|
|
|
|
// TODO(dvyukov): probably need to return this condition
|
|
|
|
// and updateSizes to caller so that Mutate can act accordingly.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
idx := g.r.Intn(len(args))
|
|
|
|
arg, base, parent := args[idx], bases[idx], parents[idx]
|
|
|
|
newCalls, ok := g.r.target.mutateArg(g.r, g.s, arg, base, parent, &updateSizes)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
2018-02-01 14:20:37 +00:00
|
|
|
calls = append(calls, newCalls...)
|
2018-01-24 18:28:36 +00:00
|
|
|
}
|
|
|
|
return calls
|
|
|
|
}
|