prog, sys: move types to prog

Large overhaul moves syscalls and arg types from sys to prog.
Sys package now depends on prog and contains only generated
descriptions of syscalls.
Introduce prog.Target type that encapsulates all targer properties,
like syscall list, ptr/page size, etc. Also moves OS-dependent pieces
like mmap call generation from prog to sys.

Update #191
This commit is contained in:
Dmitry Vyukov 2017-09-05 13:31:14 +02:00
parent 4fc4702694
commit ffe7e17368
47 changed files with 793 additions and 654 deletions

View File

@ -9,7 +9,7 @@ import (
"fmt"
"github.com/google/syzkaller/pkg/ast"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/prog"
)
func (comp *compiler) check() {
@ -191,7 +191,7 @@ func (comp *compiler) checkLenType(t *ast.Type, name string, fields []*ast.Field
}
return
}
_, args, _ := comp.getArgsBase(t, "", sys.DirIn, isArg)
_, args, _ := comp.getArgsBase(t, "", prog.DirIn, isArg)
for i, arg := range args {
argDesc := desc.Args[i]
if argDesc.Type == typeArgLenTarget {
@ -232,7 +232,7 @@ func (comp *compiler) checkLenTarget(t *ast.Type, name, target string, fields []
type structDir struct {
Struct string
Dir sys.Dir
Dir prog.Dir
}
func (comp *compiler) checkConstructors() {
@ -242,10 +242,10 @@ func (comp *compiler) checkConstructors() {
switch n := decl.(type) {
case *ast.Call:
for _, arg := range n.Args {
comp.checkTypeCtors(arg.Type, sys.DirIn, true, ctors, checked)
comp.checkTypeCtors(arg.Type, prog.DirIn, true, ctors, checked)
}
if n.Ret != nil {
comp.checkTypeCtors(n.Ret, sys.DirOut, true, ctors, checked)
comp.checkTypeCtors(n.Ret, prog.DirOut, true, ctors, checked)
}
}
}
@ -261,16 +261,16 @@ func (comp *compiler) checkConstructors() {
}
}
func (comp *compiler) checkTypeCtors(t *ast.Type, dir sys.Dir, isArg bool,
func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg bool,
ctors map[string]bool, checked map[structDir]bool) {
desc := comp.getTypeDesc(t)
if desc == typeResource {
// TODO(dvyukov): consider changing this to "dir == sys.DirOut".
// TODO(dvyukov): consider changing this to "dir == prog.DirOut".
// We have few questionable cases where resources can be created
// only by inout struct fields. These structs should be split
// into two different structs: one is in and second is out.
// But that will require attaching dir to individual fields.
if dir != sys.DirIn {
if dir != prog.DirIn {
r := comp.resources[t.Ident]
for r != nil && !ctors[r.Name.Name] {
ctors[r.Name.Name] = true
@ -376,7 +376,7 @@ func (comp *compiler) recurseField(checked map[string]bool, t *ast.Type, path []
comp.checkStructRecursion(checked, comp.structs[t.Ident], path)
return
}
_, args, base := comp.getArgsBase(t, "", sys.DirIn, false)
_, args, base := comp.getArgsBase(t, "", prog.DirIn, false)
if desc == typePtr && base.IsOptional {
return // optional pointers prune recursion
}
@ -464,7 +464,7 @@ func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceB
return
}
if desc.Check != nil {
_, args, base := comp.getArgsBase(t, "", sys.DirIn, isArg)
_, args, base := comp.getArgsBase(t, "", prog.DirIn, isArg)
desc.Check(comp, t, args, base)
}
}
@ -574,7 +574,7 @@ func (comp *compiler) checkVarlens() {
}
func (comp *compiler) isVarlen(t *ast.Type) bool {
desc, args, base := comp.getArgsBase(t, "", sys.DirIn, false)
desc, args, base := comp.getArgsBase(t, "", prog.DirIn, false)
return desc.Varlen != nil && desc.Varlen(comp, t, args, base)
}

View File

@ -12,7 +12,7 @@ import (
"strings"
"github.com/google/syzkaller/pkg/ast"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/prog"
)
// Overview of compilation process:
@ -22,20 +22,20 @@ import (
// This step also does verification of include/incdir/define AST nodes.
// 3. User translates constants to values.
// 4. Compile on AST and const values does the rest of the work and returns Prog
// containing generated sys objects.
// containing generated prog objects.
// 4.1. assignSyscallNumbers: uses consts to assign syscall numbers.
// This step also detects unsupported syscalls and discards no longer
// needed AST nodes (inlcude, define, comments, etc).
// 4.2. patchConsts: patches Int nodes refering to consts with corresponding values.
// Also detects unsupported syscalls, structs, resources due to missing consts.
// 4.3. check: does extensive semantical checks of AST.
// 4.4. gen: generates sys objects from AST.
// 4.4. gen: generates prog objects from AST.
// Prog is description compilation result.
type Prog struct {
Resources []*sys.ResourceDesc
Syscalls []*sys.Syscall
StructDescs []*sys.KeyedStruct
Resources []*prog.ResourceDesc
Syscalls []*prog.Syscall
StructDescs []*prog.KeyedStruct
// Set of unsupported syscalls/flags.
Unsupported map[string]bool
}
@ -54,8 +54,8 @@ func Compile(desc *ast.Description, consts map[string]uint64, ptrSize uint64, eh
structs: make(map[string]*ast.Struct),
intFlags: make(map[string]*ast.IntFlags),
strFlags: make(map[string]*ast.StrFlags),
structDescs: make(map[sys.StructKey]*sys.StructDesc),
structNodes: make(map[*sys.StructDesc]*ast.Struct),
structDescs: make(map[prog.StructKey]*prog.StructDesc),
structNodes: make(map[*prog.StructDesc]*ast.Struct),
structVarlen: make(map[string]bool),
}
comp.assignSyscallNumbers(consts)
@ -89,8 +89,8 @@ type compiler struct {
intFlags map[string]*ast.IntFlags
strFlags map[string]*ast.StrFlags
structDescs map[sys.StructKey]*sys.StructDesc
structNodes map[*sys.StructDesc]*ast.Struct
structDescs map[prog.StructKey]*prog.StructDesc
structNodes map[*prog.StructDesc]*ast.Struct
structVarlen map[string]bool
}
@ -161,8 +161,8 @@ func (comp *compiler) getTypeDesc(t *ast.Type) *typeDesc {
return nil
}
func (comp *compiler) getArgsBase(t *ast.Type, field string, dir sys.Dir, isArg bool) (
*typeDesc, []*ast.Type, sys.IntTypeCommon) {
func (comp *compiler) getArgsBase(t *ast.Type, field string, dir prog.Dir, isArg bool) (
*typeDesc, []*ast.Type, prog.IntTypeCommon) {
desc := comp.getTypeDesc(t)
args, opt := removeOpt(t)
size := sizeUnassigned
@ -173,7 +173,7 @@ func (comp *compiler) getArgsBase(t *ast.Type, field string, dir sys.Dir, isArg
if !isArg {
baseType := args[len(args)-1]
args = args[:len(args)-1]
base = typeInt.Gen(comp, baseType, nil, base).(*sys.IntType).IntTypeCommon
base = typeInt.Gen(comp, baseType, nil, base).(*prog.IntType).IntTypeCommon
}
}
return desc, args, base

View File

@ -8,13 +8,13 @@ import (
"sort"
"github.com/google/syzkaller/pkg/ast"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/prog"
)
const sizeUnassigned = ^uint64(0)
func (comp *compiler) genResources() []*sys.ResourceDesc {
var resources []*sys.ResourceDesc
func (comp *compiler) genResources() []*prog.ResourceDesc {
var resources []*prog.ResourceDesc
for _, decl := range comp.desc.Nodes {
if n, ok := decl.(*ast.Resource); ok {
resources = append(resources, comp.genResource(n))
@ -26,8 +26,8 @@ func (comp *compiler) genResources() []*sys.ResourceDesc {
return resources
}
func (comp *compiler) genResource(n *ast.Resource) *sys.ResourceDesc {
res := &sys.ResourceDesc{
func (comp *compiler) genResource(n *ast.Resource) *prog.ResourceDesc {
res := &prog.ResourceDesc{
Name: n.Name.Name,
}
var base *ast.Type
@ -40,12 +40,12 @@ func (comp *compiler) genResource(n *ast.Resource) *sys.ResourceDesc {
if len(res.Values) == 0 {
res.Values = []uint64{0}
}
res.Type = comp.genType(base, "", sys.DirIn, false)
res.Type = comp.genType(base, "", prog.DirIn, false)
return res
}
func (comp *compiler) genSyscalls() []*sys.Syscall {
var calls []*sys.Syscall
func (comp *compiler) genSyscalls() []*prog.Syscall {
var calls []*prog.Syscall
for _, decl := range comp.desc.Nodes {
if n, ok := decl.(*ast.Call); ok {
calls = append(calls, comp.genSyscall(n))
@ -60,32 +60,32 @@ func (comp *compiler) genSyscalls() []*sys.Syscall {
return calls
}
func (comp *compiler) genSyscall(n *ast.Call) *sys.Syscall {
var ret sys.Type
func (comp *compiler) genSyscall(n *ast.Call) *prog.Syscall {
var ret prog.Type
if n.Ret != nil {
ret = comp.genType(n.Ret, "ret", sys.DirOut, true)
ret = comp.genType(n.Ret, "ret", prog.DirOut, true)
}
return &sys.Syscall{
return &prog.Syscall{
Name: n.Name.Name,
CallName: n.CallName,
NR: n.NR,
Args: comp.genFieldArray(n.Args, sys.DirIn, true),
Args: comp.genFieldArray(n.Args, prog.DirIn, true),
Ret: ret,
}
}
func (comp *compiler) genStructDescs(syscalls []*sys.Syscall) []*sys.KeyedStruct {
func (comp *compiler) genStructDescs(syscalls []*prog.Syscall) []*prog.KeyedStruct {
// Calculate struct/union/array sizes, add padding to structs and detach
// StructDesc's from StructType's. StructType's can be recursive so it's
// not possible to write them out inline as other types. To break the
// recursion detach them, and write StructDesc's out as separate array
// of KeyedStruct's. sys package will reattach them during init.
// of KeyedStruct's. prog package will reattach them during init.
padded := make(map[interface{}]bool)
detach := make(map[**sys.StructDesc]bool)
var structs []*sys.KeyedStruct
var rec func(t sys.Type)
checkStruct := func(key sys.StructKey, descp **sys.StructDesc) bool {
detach := make(map[**prog.StructDesc]bool)
var structs []*prog.KeyedStruct
var rec func(t prog.Type)
checkStruct := func(key prog.StructKey, descp **prog.StructDesc) bool {
detach[descp] = true
desc := *descp
if padded[desc] {
@ -101,17 +101,17 @@ func (comp *compiler) genStructDescs(syscalls []*sys.Syscall) []*sys.KeyedStruct
return false
}
}
structs = append(structs, &sys.KeyedStruct{
structs = append(structs, &prog.KeyedStruct{
Key: key,
Desc: desc,
})
return true
}
rec = func(t0 sys.Type) {
rec = func(t0 prog.Type) {
switch t := t0.(type) {
case *sys.PtrType:
case *prog.PtrType:
rec(t.Type)
case *sys.ArrayType:
case *prog.ArrayType:
if padded[t] {
return
}
@ -123,10 +123,10 @@ func (comp *compiler) genStructDescs(syscalls []*sys.Syscall) []*sys.KeyedStruct
}
padded[t] = true
t.TypeSize = 0
if t.Kind == sys.ArrayRangeLen && t.RangeBegin == t.RangeEnd && !t.Type.Varlen() {
if t.Kind == prog.ArrayRangeLen && t.RangeBegin == t.RangeEnd && !t.Type.Varlen() {
t.TypeSize = t.RangeBegin * t.Type.Size()
}
case *sys.StructType:
case *prog.StructType:
if !checkStruct(t.Key, &t.StructDesc) {
return
}
@ -149,7 +149,7 @@ func (comp *compiler) genStructDescs(syscalls []*sys.Syscall) []*sys.KeyedStruct
}
}
}
case *sys.UnionType:
case *prog.UnionType:
if !checkStruct(t.Key, &t.StructDesc) {
return
}
@ -182,7 +182,7 @@ func (comp *compiler) genStructDescs(syscalls []*sys.Syscall) []*sys.KeyedStruct
}
}
// Detach StructDesc's from StructType's. sys will reattach them again.
// Detach StructDesc's from StructType's. prog will reattach them again.
for descp := range detach {
*descp = nil
}
@ -197,10 +197,10 @@ func (comp *compiler) genStructDescs(syscalls []*sys.Syscall) []*sys.KeyedStruct
return structs
}
func (comp *compiler) genStructDesc(res *sys.StructDesc, n *ast.Struct, dir sys.Dir) {
func (comp *compiler) genStructDesc(res *prog.StructDesc, n *ast.Struct, dir prog.Dir) {
// Leave node for genStructDescs to calculate size/padding.
comp.structNodes[res] = n
*res = sys.StructDesc{
*res = prog.StructDesc{
TypeCommon: genCommon(n.Name.Name, "", sizeUnassigned, dir, false),
Fields: comp.genFieldArray(n.Fields, dir, false),
}
@ -227,7 +227,7 @@ func (comp *compiler) isStructVarlen(name string) bool {
return varlen
}
func (comp *compiler) markBitfields(fields []sys.Type) {
func (comp *compiler) markBitfields(fields []prog.Type) {
var bfOffset uint64
for i, f := range fields {
if f.BitfieldLength() == 0 {
@ -245,25 +245,25 @@ func (comp *compiler) markBitfields(fields []sys.Type) {
}
}
func setBitfieldOffset(t0 sys.Type, offset uint64, middle bool) {
func setBitfieldOffset(t0 prog.Type, offset uint64, middle bool) {
switch t := t0.(type) {
case *sys.IntType:
case *prog.IntType:
t.BitfieldOff, t.BitfieldMdl = offset, middle
case *sys.ConstType:
case *prog.ConstType:
t.BitfieldOff, t.BitfieldMdl = offset, middle
case *sys.LenType:
case *prog.LenType:
t.BitfieldOff, t.BitfieldMdl = offset, middle
case *sys.FlagsType:
case *prog.FlagsType:
t.BitfieldOff, t.BitfieldMdl = offset, middle
case *sys.ProcType:
case *prog.ProcType:
t.BitfieldOff, t.BitfieldMdl = offset, middle
default:
panic(fmt.Sprintf("type %#v can't be a bitfield", t))
}
}
func (comp *compiler) addAlignment(fields []sys.Type, varlen, packed bool, alignAttr uint64) []sys.Type {
var newFields []sys.Type
func (comp *compiler) addAlignment(fields []prog.Type, varlen, packed bool, alignAttr uint64) []prog.Type {
var newFields []prog.Type
if packed {
// If a struct is packed, statically sized and has explicitly set alignment,
// add a padding at the end.
@ -312,19 +312,19 @@ func (comp *compiler) addAlignment(fields []sys.Type, varlen, packed bool, align
return newFields
}
func (comp *compiler) typeAlign(t0 sys.Type) uint64 {
func (comp *compiler) typeAlign(t0 prog.Type) uint64 {
switch t0.(type) {
case *sys.IntType, *sys.ConstType, *sys.LenType, *sys.FlagsType, *sys.ProcType,
*sys.CsumType, *sys.PtrType, *sys.VmaType, *sys.ResourceType:
case *prog.IntType, *prog.ConstType, *prog.LenType, *prog.FlagsType, *prog.ProcType,
*prog.CsumType, *prog.PtrType, *prog.VmaType, *prog.ResourceType:
return t0.Size()
case *sys.BufferType:
case *prog.BufferType:
return 1
}
switch t := t0.(type) {
case *sys.ArrayType:
case *prog.ArrayType:
return comp.typeAlign(t.Type)
case *sys.StructType:
case *prog.StructType:
packed, alignAttr := comp.parseStructAttrs(comp.structNodes[t.StructDesc])
if alignAttr != 0 {
return alignAttr // overrided by user attribute
@ -339,7 +339,7 @@ func (comp *compiler) typeAlign(t0 sys.Type) uint64 {
}
}
return align
case *sys.UnionType:
case *prog.UnionType:
align := uint64(0)
for _, f := range t.Fields {
if a := comp.typeAlign(f); align < a {
@ -352,32 +352,32 @@ func (comp *compiler) typeAlign(t0 sys.Type) uint64 {
}
}
func genPad(size uint64) sys.Type {
return &sys.ConstType{
IntTypeCommon: genIntCommon(genCommon("pad", "", size, sys.DirIn, false), 0, false),
func genPad(size uint64) prog.Type {
return &prog.ConstType{
IntTypeCommon: genIntCommon(genCommon("pad", "", size, prog.DirIn, false), 0, false),
IsPad: true,
}
}
func (comp *compiler) genField(f *ast.Field, dir sys.Dir, isArg bool) sys.Type {
func (comp *compiler) genField(f *ast.Field, dir prog.Dir, isArg bool) prog.Type {
return comp.genType(f.Type, f.Name.Name, dir, isArg)
}
func (comp *compiler) genFieldArray(fields []*ast.Field, dir sys.Dir, isArg bool) []sys.Type {
var res []sys.Type
func (comp *compiler) genFieldArray(fields []*ast.Field, dir prog.Dir, isArg bool) []prog.Type {
var res []prog.Type
for _, f := range fields {
res = append(res, comp.genField(f, dir, isArg))
}
return res
}
func (comp *compiler) genType(t *ast.Type, field string, dir sys.Dir, isArg bool) sys.Type {
func (comp *compiler) genType(t *ast.Type, field string, dir prog.Dir, isArg bool) prog.Type {
desc, args, base := comp.getArgsBase(t, field, dir, isArg)
return desc.Gen(comp, t, args, base)
}
func genCommon(name, field string, size uint64, dir sys.Dir, opt bool) sys.TypeCommon {
return sys.TypeCommon{
func genCommon(name, field string, size uint64, dir prog.Dir, opt bool) prog.TypeCommon {
return prog.TypeCommon{
TypeName: name,
TypeSize: size,
FldName: field,
@ -386,8 +386,8 @@ func genCommon(name, field string, size uint64, dir sys.Dir, opt bool) sys.TypeC
}
}
func genIntCommon(com sys.TypeCommon, bitLen uint64, bigEndian bool) sys.IntTypeCommon {
return sys.IntTypeCommon{
func genIntCommon(com prog.TypeCommon, bitLen uint64, bigEndian bool) prog.IntTypeCommon {
return prog.IntTypeCommon{
TypeCommon: com,
BigEndian: bigEndian,
BitfieldLen: bitLen,

View File

@ -8,7 +8,7 @@ import (
"strconv"
"github.com/google/syzkaller/pkg/ast"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/prog"
)
// typeDesc is arg/field type descriptor.
@ -23,11 +23,11 @@ type typeDesc struct {
OptArgs int // number of optional arguments in Args array
Args []namedArg // type arguments
// Check does custom verification of the type (optional).
Check func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon)
Check func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon)
// Varlen returns if the type is variable-length (false if not set).
Varlen func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) bool
// Gen generates corresponding sys.Type.
Gen func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type
Varlen func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) bool
// Gen generates corresponding prog.Type.
Gen func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type
}
// typeArg describes a type argument.
@ -58,17 +58,17 @@ var typeInt = &typeDesc{
ResourceBase: true,
OptArgs: 1,
Args: []namedArg{{"range", typeArgRange}},
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) {
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
typeArgBase.Type.Check(comp, t)
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
size, be := comp.parseIntType(t.Ident)
kind, rangeBegin, rangeEnd := sys.IntPlain, uint64(0), uint64(0)
kind, rangeBegin, rangeEnd := prog.IntPlain, uint64(0), uint64(0)
if len(args) > 0 {
kind, rangeBegin, rangeEnd = sys.IntRange, args[0].Value, args[0].Value2
kind, rangeBegin, rangeEnd = prog.IntRange, args[0].Value, args[0].Value2
}
base.TypeSize = size
return &sys.IntType{
return &prog.IntType{
IntTypeCommon: genIntCommon(base.TypeCommon, t.Value2, be),
Kind: kind,
RangeBegin: rangeBegin,
@ -81,13 +81,13 @@ var typePtr = &typeDesc{
Names: []string{"ptr", "ptr64"},
CanBeArg: true,
Args: []namedArg{{"direction", typeArgDir}, {"type", typeArgType}},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
base.ArgDir = sys.DirIn // pointers are always in
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.ArgDir = prog.DirIn // pointers are always in
base.TypeSize = comp.ptrSize
if t.Ident == "ptr64" {
base.TypeSize = 8
}
return &sys.PtrType{
return &prog.PtrType{
TypeCommon: base.TypeCommon,
Type: comp.genType(args[1], "", genDir(args[0]), false),
}
@ -99,13 +99,13 @@ var typeArray = &typeDesc{
CantBeOpt: true,
OptArgs: 1,
Args: []namedArg{{"type", typeArgType}, {"size", typeArgRange}},
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) {
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
if len(args) > 1 && args[1].Value == 0 && args[1].Value2 == 0 {
// This is the only case that can yield 0 static type size.
comp.error(args[1].Pos, "arrays of size 0 are not supported")
}
},
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) bool {
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) bool {
if comp.isVarlen(args[0]) {
return true
}
@ -114,23 +114,23 @@ var typeArray = &typeDesc{
}
return true
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
elemType := comp.genType(args[0], "", base.ArgDir, false)
kind, begin, end := sys.ArrayRandLen, uint64(0), uint64(0)
kind, begin, end := prog.ArrayRandLen, uint64(0), uint64(0)
if len(args) > 1 {
kind, begin, end = sys.ArrayRangeLen, args[1].Value, args[1].Value2
kind, begin, end = prog.ArrayRangeLen, args[1].Value, args[1].Value2
}
if it, ok := elemType.(*sys.IntType); ok && it.Kind == sys.IntPlain && it.TypeSize == 1 {
if it, ok := elemType.(*prog.IntType); ok && it.Kind == prog.IntPlain && it.TypeSize == 1 {
// Special case: buffer is better mutated.
bufKind := sys.BufferBlobRand
bufKind := prog.BufferBlobRand
base.TypeSize = 0
if kind == sys.ArrayRangeLen {
bufKind = sys.BufferBlobRange
if kind == prog.ArrayRangeLen {
bufKind = prog.BufferBlobRange
if begin == end {
base.TypeSize = begin * elemType.Size()
}
}
return &sys.BufferType{
return &prog.BufferType{
TypeCommon: base.TypeCommon,
Kind: bufKind,
RangeBegin: begin,
@ -138,7 +138,7 @@ var typeArray = &typeDesc{
}
}
// TypeSize is assigned later in genStructDescs.
return &sys.ArrayType{
return &prog.ArrayType{
TypeCommon: base.TypeCommon,
Type: elemType,
Kind: kind,
@ -155,7 +155,7 @@ var typeLen = &typeDesc{
CantBeRet: true,
NeedBase: true,
Args: []namedArg{{"len target", typeArgLenTarget}},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
var byteSize uint64
switch t.Ident {
case "bytesize":
@ -163,7 +163,7 @@ var typeLen = &typeDesc{
case "bytesize2", "bytesize4", "bytesize8":
byteSize, _ = strconv.ParseUint(t.Ident[8:], 10, 8)
}
return &sys.LenType{
return &prog.LenType{
IntTypeCommon: base,
Buf: args[0].Ident,
ByteSize: byteSize,
@ -177,8 +177,8 @@ var typeConst = &typeDesc{
CantBeOpt: true,
NeedBase: true,
Args: []namedArg{{"value", typeArgInt}},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
return &sys.ConstType{
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
return &prog.ConstType{
IntTypeCommon: base,
Val: args[0].Value,
}
@ -195,18 +195,18 @@ var typeFlags = &typeDesc{
CantBeOpt: true,
NeedBase: true,
Args: []namedArg{{"flags", typeArgFlags}},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
name := args[0].Ident
base.TypeName = name
f := comp.intFlags[name]
if len(f.Values) == 0 {
// We can get this if all values are unsupported consts.
return &sys.IntType{
return &prog.IntType{
IntTypeCommon: base,
Kind: sys.IntPlain,
Kind: prog.IntPlain,
}
}
return &sys.FlagsType{
return &prog.FlagsType{
IntTypeCommon: base,
Vals: genIntArray(f.Values),
}
@ -226,14 +226,14 @@ var typeArgFlags = &typeArg{
var typeFilename = &typeDesc{
Names: []string{"filename"},
CantBeOpt: true,
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) bool {
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) bool {
return true
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeSize = 0
return &sys.BufferType{
return &prog.BufferType{
TypeCommon: base.TypeCommon,
Kind: sys.BufferFilename,
Kind: prog.BufferFilename,
}
},
}
@ -243,10 +243,10 @@ var typeFileoff = &typeDesc{
CanBeArg: true,
CantBeOpt: true,
NeedBase: true,
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
return &sys.IntType{
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
return &prog.IntType{
IntTypeCommon: base,
Kind: sys.IntFileoff,
Kind: prog.IntFileoff,
}
},
}
@ -256,13 +256,13 @@ var typeVMA = &typeDesc{
CanBeArg: true,
OptArgs: 1,
Args: []namedArg{{"size range", typeArgRange}},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
begin, end := uint64(0), uint64(0)
if len(args) > 0 {
begin, end = args[0].Value, args[0].Value2
}
base.TypeSize = comp.ptrSize
return &sys.VmaType{
return &prog.VmaType{
TypeCommon: base.TypeCommon,
RangeBegin: begin,
RangeEnd: end,
@ -277,11 +277,11 @@ var typeSignalno = &typeDesc{
Names: []string{"signalno"},
CanBeArg: true,
CantBeOpt: true,
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeSize = 4
return &sys.IntType{
return &prog.IntType{
IntTypeCommon: base,
Kind: sys.IntRange,
Kind: prog.IntRange,
RangeBegin: 0,
RangeEnd: 65,
}
@ -295,17 +295,17 @@ var typeCsum = &typeDesc{
CantBeRet: true,
OptArgs: 1,
Args: []namedArg{{"csum target", typeArgLenTarget}, {"kind", typeArgCsumType}, {"proto", typeArgInt}},
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) {
if len(args) > 2 && genCsumKind(args[1]) != sys.CsumPseudo {
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
if len(args) > 2 && genCsumKind(args[1]) != prog.CsumPseudo {
comp.error(args[2].Pos, "only pseudo csum can have proto")
}
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
var proto uint64
if len(args) > 2 {
proto = args[2].Value
}
return &sys.CsumType{
return &prog.CsumType{
IntTypeCommon: base,
Buf: args[0].Ident,
Kind: genCsumKind(args[1]),
@ -319,12 +319,12 @@ var typeArgCsumType = &typeArg{
Names: []string{"inet", "pseudo"},
}
func genCsumKind(t *ast.Type) sys.CsumKind {
func genCsumKind(t *ast.Type) prog.CsumKind {
switch t.Ident {
case "inet":
return sys.CsumInet
return prog.CsumInet
case "pseudo":
return sys.CsumPseudo
return prog.CsumPseudo
default:
panic(fmt.Sprintf("unknown csum kind %q", t.Ident))
}
@ -336,7 +336,7 @@ var typeProc = &typeDesc{
CantBeOpt: true,
NeedBase: true,
Args: []namedArg{{"range start", typeArgInt}, {"per-proc values", typeArgInt}},
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) {
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
start := args[0].Value
perProc := args[1].Value
if perProc == 0 {
@ -354,8 +354,8 @@ var typeProc = &typeDesc{
}
}
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
return &sys.ProcType{
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
return &prog.ProcType{
IntTypeCommon: base,
ValuesStart: args[0].Value,
ValuesPerProc: args[1].Value,
@ -367,14 +367,14 @@ var typeText = &typeDesc{
Names: []string{"text"},
CantBeOpt: true,
Args: []namedArg{{"kind", typeArgTextType}},
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) bool {
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) bool {
return true
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeSize = 0
return &sys.BufferType{
return &prog.BufferType{
TypeCommon: base.TypeCommon,
Kind: sys.BufferText,
Kind: prog.BufferText,
Text: genTextType(args[0]),
}
},
@ -385,18 +385,18 @@ var typeArgTextType = &typeArg{
Names: []string{"x86_real", "x86_16", "x86_32", "x86_64", "arm64"},
}
func genTextType(t *ast.Type) sys.TextKind {
func genTextType(t *ast.Type) prog.TextKind {
switch t.Ident {
case "x86_real":
return sys.Text_x86_real
return prog.Text_x86_real
case "x86_16":
return sys.Text_x86_16
return prog.Text_x86_16
case "x86_32":
return sys.Text_x86_32
return prog.Text_x86_32
case "x86_64":
return sys.Text_x86_64
return prog.Text_x86_64
case "arm64":
return sys.Text_arm64
return prog.Text_arm64
default:
panic(fmt.Sprintf("unknown text type %q", t.Ident))
}
@ -406,14 +406,14 @@ var typeBuffer = &typeDesc{
Names: []string{"buffer"},
CanBeArg: true,
Args: []namedArg{{"direction", typeArgDir}},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
base.TypeSize = comp.ptrSize
return &sys.PtrType{
return &prog.PtrType{
TypeCommon: base.TypeCommon,
Type: &sys.BufferType{
Type: &prog.BufferType{
// BufferBlobRand is always varlen.
TypeCommon: genCommon("", "", 0, genDir(args[0]), false),
Kind: sys.BufferBlobRand,
Kind: prog.BufferBlobRand,
},
}
},
@ -423,7 +423,7 @@ var typeString = &typeDesc{
Names: []string{"string"},
OptArgs: 2,
Args: []namedArg{{"literal or flags", typeArgStringFlags}, {"size", typeArgInt}},
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) {
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
if len(args) > 1 {
size := args[1].Value
vals := []string{args[0].String}
@ -439,10 +439,10 @@ var typeString = &typeDesc{
}
}
},
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) bool {
Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) bool {
return comp.stringSize(args) == 0
},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
subkind := ""
var vals []string
if len(args) > 0 {
@ -465,9 +465,9 @@ var typeString = &typeDesc{
vals[i] = s
}
base.TypeSize = comp.stringSize(args)
return &sys.BufferType{
return &prog.BufferType{
TypeCommon: base.TypeCommon,
Kind: sys.BufferString,
Kind: prog.BufferString,
SubKind: subkind,
Values: vals,
}
@ -527,15 +527,15 @@ var typeResource = &typeDesc{
}
func init() {
typeResource.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
typeResource.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
// Find and generate base type to get its size.
var baseType *ast.Type
for r := comp.resources[t.Ident]; r != nil; {
baseType = r.Base
r = comp.resources[r.Base.Ident]
}
base.TypeSize = comp.genType(baseType, "", sys.DirIn, false).Size()
return &sys.ResourceType{
base.TypeSize = comp.genType(baseType, "", prog.DirIn, false).Size()
return &prog.ResourceType{
TypeCommon: base.TypeCommon,
}
}
@ -548,27 +548,27 @@ var typeStruct = &typeDesc{
}
func init() {
typeStruct.Varlen = func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) bool {
typeStruct.Varlen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) bool {
return comp.isStructVarlen(t.Ident)
}
typeStruct.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base sys.IntTypeCommon) sys.Type {
typeStruct.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
s := comp.structs[t.Ident]
key := sys.StructKey{t.Ident, base.ArgDir}
key := prog.StructKey{t.Ident, base.ArgDir}
desc := comp.structDescs[key]
if desc == nil {
// Need to assign to structDescs before calling genStructDesc to break recursion.
desc = new(sys.StructDesc)
desc = new(prog.StructDesc)
comp.structDescs[key] = desc
comp.genStructDesc(desc, s, base.ArgDir)
}
if s.IsUnion {
return &sys.UnionType{
return &prog.UnionType{
Key: key,
FldName: base.FldName,
StructDesc: desc,
}
} else {
return &sys.StructType{
return &prog.StructType{
Key: key,
FldName: base.FldName,
StructDesc: desc,
@ -582,14 +582,14 @@ var typeArgDir = &typeArg{
Names: []string{"in", "out", "inout"},
}
func genDir(t *ast.Type) sys.Dir {
func genDir(t *ast.Type) prog.Dir {
switch t.Ident {
case "in":
return sys.DirIn
return prog.DirIn
case "out":
return sys.DirOut
return prog.DirOut
case "inout":
return sys.DirInOut
return prog.DirInOut
default:
panic(fmt.Sprintf("unknown direction %q", t.Ident))
}

View File

@ -20,7 +20,7 @@ import (
"unsafe"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys"
_ "github.com/google/syzkaller/sys"
)
type Options struct {
@ -367,7 +367,7 @@ loop:
fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_futex/ignore-private\", \"N\");\n")
fmt.Fprintf(w, "\tinject_fault(%v);\n", opts.FaultNth)
}
meta := sys.Syscalls[instr]
meta := prog.Syscalls[instr]
emitCall := true
if meta.CallName == "syz_test" {
emitCall = false

View File

@ -13,6 +13,7 @@ import (
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
func initTest(t *testing.T) (rand.Source, int) {

View File

@ -12,13 +12,13 @@ import (
"syscall"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/prog"
)
// DetectSupportedSyscalls returns list on supported syscalls on host.
func DetectSupportedSyscalls() (map[*sys.Syscall]bool, error) {
func DetectSupportedSyscalls() (map[*prog.Syscall]bool, error) {
// There are 3 possible strategies:
// 1. Executes all syscalls with presumably invalid arguments and check for ENOSYS.
// 1. Executes all syscalls with presumably invalid arguments and check for ENOprog.
// But not all syscalls are safe to execute. For example, pause will hang,
// while setpgrp will push the process into own process group.
// 2. Check presence of /sys/kernel/debug/tracing/events/syscalls/sys_enter_* files.
@ -28,8 +28,8 @@ func DetectSupportedSyscalls() (map[*sys.Syscall]bool, error) {
// Requires CONFIG_KALLSYMS. Seems to be the most reliable. That's what we use here.
kallsyms, _ := ioutil.ReadFile("/proc/kallsyms")
supported := make(map[*sys.Syscall]bool)
for _, c := range sys.Syscalls {
supported := make(map[*prog.Syscall]bool)
for _, c := range prog.Syscalls {
if isSupported(kallsyms, c) {
supported[c] = true
}
@ -37,7 +37,7 @@ func DetectSupportedSyscalls() (map[*sys.Syscall]bool, error) {
return supported, nil
}
func isSupported(kallsyms []byte, c *sys.Syscall) bool {
func isSupported(kallsyms []byte, c *prog.Syscall) bool {
if c.NR == ^uint64(0) {
return false // don't even have a syscall number
}
@ -59,12 +59,12 @@ func isSupported(kallsyms []byte, c *sys.Syscall) bool {
return bytes.Index(kallsyms, []byte(" T sys_"+c.CallName+"\n")) != -1
}
func isSupportedSyzkall(c *sys.Syscall) bool {
func isSupportedSyzkall(c *prog.Syscall) bool {
switch c.CallName {
case "syz_test":
return false
case "syz_open_dev":
if _, ok := c.Args[0].(*sys.ConstType); ok {
if _, ok := c.Args[0].(*prog.ConstType); ok {
// This is for syz_open_dev$char/block.
// They are currently commented out, but in case one enables them.
return true
@ -112,8 +112,8 @@ func isSupportedSyzkall(c *sys.Syscall) bool {
panic("unknown syzkall: " + c.Name)
}
func isSupportedSocket(c *sys.Syscall) bool {
af, ok := c.Args[0].(*sys.ConstType)
func isSupportedSocket(c *prog.Syscall) bool {
af, ok := c.Args[0].(*prog.ConstType)
if !ok {
println(c.Name)
panic("socket family is not const")
@ -125,7 +125,7 @@ func isSupportedSocket(c *sys.Syscall) bool {
return err != syscall.ENOSYS && err != syscall.EAFNOSUPPORT
}
func isSupportedOpen(c *sys.Syscall) bool {
func isSupportedOpen(c *prog.Syscall) bool {
fname, ok := extractStringConst(c.Args[0])
if !ok {
return true
@ -137,7 +137,7 @@ func isSupportedOpen(c *sys.Syscall) bool {
return err == nil
}
func isSupportedOpenAt(c *sys.Syscall) bool {
func isSupportedOpenAt(c *prog.Syscall) bool {
fname, ok := extractStringConst(c.Args[1])
if !ok {
return true
@ -149,13 +149,13 @@ func isSupportedOpenAt(c *sys.Syscall) bool {
return err == nil
}
func extractStringConst(typ sys.Type) (string, bool) {
ptr, ok := typ.(*sys.PtrType)
func extractStringConst(typ prog.Type) (string, bool) {
ptr, ok := typ.(*prog.PtrType)
if !ok {
panic("first open arg is not a pointer to string const")
}
str, ok := ptr.Type.(*sys.BufferType)
if !ok || str.Kind != sys.BufferString || len(str.Values) != 1 {
str, ok := ptr.Type.(*prog.BufferType)
if !ok || str.Kind != prog.BufferString || len(str.Values) != 1 {
return "", false
}
v := str.Values[0]

View File

@ -7,7 +7,8 @@ import (
"syscall"
"testing"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
func TestLog(t *testing.T) {
@ -18,7 +19,7 @@ func TestLog(t *testing.T) {
t.Skipf("skipping: %v", err)
}
t.Logf("unsupported:")
for _, c := range sys.Syscalls {
for _, c := range prog.Syscalls {
s, ok := supp[c]
if ok && !s {
t.Fatalf("map contains false value")
@ -27,9 +28,9 @@ func TestLog(t *testing.T) {
t.Logf("\t%v", c.Name)
}
}
trans := sys.TransitivelyEnabledCalls(supp)
trans := prog.TransitivelyEnabledCalls(supp)
t.Logf("transitively unsupported:")
for _, c := range sys.Syscalls {
for _, c := range prog.Syscalls {
s, ok := trans[c]
if ok && !s {
t.Fatalf("map contains false value")
@ -58,7 +59,7 @@ func TestSupportedSyscalls(t *testing.T) {
"stat",
}
for _, name := range safe {
c := sys.SyscallMap[name]
c := prog.SyscallMap[name]
if c == nil {
t.Fatalf("can't find syscall '%v'", name)
}

View File

@ -13,6 +13,7 @@ import (
"github.com/google/syzkaller/pkg/csource"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
const timeout = 10 * time.Second

View File

@ -10,8 +10,6 @@ package prog
import (
"fmt"
. "github.com/google/syzkaller/sys"
)
const (
@ -68,43 +66,15 @@ func (s *state) analyze(c *Call) {
}
}
})
switch c.Meta.Name {
case "mmap":
// Filter out only very wrong arguments.
length := c.Args[1].(*ConstArg)
if length.Val == 0 {
break
start, npages, mapped := analyzeMmap(c)
if npages != 0 {
if start+npages > uint64(len(s.pages)) {
panic(fmt.Sprintf("address is out of bounds: page=%v len=%v bound=%v",
start, npages, len(s.pages)))
}
flags := c.Args[3].(*ConstArg)
fd := c.Args[4].(*ResultArg)
if flags.Val&MAP_ANONYMOUS == 0 && fd.Val == InvalidFD {
break
for i := uint64(0); i < npages; i++ {
s.pages[start+i] = mapped
}
s.addressable(c.Args[0].(*PointerArg), length, true)
case "munmap":
s.addressable(c.Args[0].(*PointerArg), c.Args[1].(*ConstArg), false)
case "mremap":
s.addressable(c.Args[4].(*PointerArg), c.Args[2].(*ConstArg), true)
case "io_submit":
if arr := c.Args[2].(*PointerArg).Res; arr != nil {
for _, ptr := range arr.(*GroupArg).Inner {
p := ptr.(*PointerArg)
if p.Res != nil && p.Res.Type().Name() == "iocb" {
s.resources["iocbptr"] = append(s.resources["iocbptr"], ptr)
}
}
}
}
}
func (s *state) addressable(addr *PointerArg, size *ConstArg, ok bool) {
sizePages := size.Val / pageSize
if addr.PageIndex+sizePages > uint64(len(s.pages)) {
panic(fmt.Sprintf("address is out of bounds: page=%v len=%v bound=%v\naddr: %+v\nsize: %+v",
addr.PageIndex, sizePages, len(s.pages), addr, size))
}
for i := uint64(0); i < sizePages; i++ {
s.pages[addr.PageIndex+i] = ok
}
}
@ -181,86 +151,6 @@ func foreachSubargOffset(arg Arg, f func(arg Arg, offset uint64)) {
rec(arg, 0)
}
func sanitizeCall(c *Call) {
switch c.Meta.CallName {
case "mmap":
// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
_, ok := c.Args[0].(*PointerArg)
if !ok {
panic("mmap address is not ArgPointer")
}
_, ok = c.Args[1].(*ConstArg)
if !ok {
panic("mmap length is not ArgPageSize")
}
flags, ok := c.Args[3].(*ConstArg)
if !ok {
panic("mmap flag arg is not const")
}
flags.Val |= MAP_FIXED
case "mremap":
// Add MREMAP_FIXED flag, otherwise it produces non-deterministic results.
flags, ok := c.Args[3].(*ConstArg)
if !ok {
panic("mremap flag arg is not const")
}
if flags.Val&MREMAP_MAYMOVE != 0 {
flags.Val |= MREMAP_FIXED
}
case "mknod", "mknodat":
mode, ok1 := c.Args[1].(*ConstArg)
dev, ok2 := c.Args[2].(*ConstArg)
if c.Meta.CallName == "mknodat" {
mode, ok1 = c.Args[2].(*ConstArg)
dev, ok2 = c.Args[3].(*ConstArg)
}
if !ok1 || !ok2 {
panic("mknod mode is not const")
}
// Char and block devices read/write io ports, kernel memory and do other nasty things.
// TODO: not required if executor drops privileges.
switch mode.Val & (S_IFREG | S_IFCHR | S_IFBLK | S_IFIFO | S_IFSOCK) {
case S_IFREG, S_IFIFO, S_IFSOCK:
case S_IFBLK:
if dev.Val>>8 == 7 {
break // loop
}
mode.Val &^= S_IFBLK
mode.Val |= S_IFREG
case S_IFCHR:
mode.Val &^= S_IFCHR
mode.Val |= S_IFREG
}
case "syslog":
cmd := c.Args[0].(*ConstArg)
// These disable console output, but we need it.
if cmd.Val == SYSLOG_ACTION_CONSOLE_OFF || cmd.Val == SYSLOG_ACTION_CONSOLE_ON {
cmd.Val = SYSLOG_ACTION_SIZE_UNREAD
}
case "ioctl":
cmd := c.Args[1].(*ConstArg)
// Freeze kills machine. Though, it is an interesting functions,
// so we need to test it somehow.
// TODO: not required if executor drops privileges.
if uint32(cmd.Val) == FIFREEZE {
cmd.Val = FITHAW
}
case "ptrace":
req := c.Args[0].(*ConstArg)
// PTRACE_TRACEME leads to unkillable processes, see:
// https://groups.google.com/forum/#!topic/syzkaller/uGzwvhlCXAw
if req.Val == PTRACE_TRACEME {
req.Val = ^uint64(0)
}
case "exit", "exit_group":
code := c.Args[0].(*ConstArg)
// These codes are reserved by executor.
if code.Val%128 == 67 || code.Val%128 == 68 {
code.Val = 1
}
}
}
func RequiresBitmasks(p *Prog) bool {
result := false
for _, c := range p.Calls {

View File

@ -5,8 +5,6 @@ package prog
import (
"fmt"
. "github.com/google/syzkaller/sys"
)
type CsumChunkKind int

View File

@ -1,23 +1,26 @@
// Copyright 2016 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
package prog_test
import (
"testing"
. "github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
func TestChecksumCalcRandom(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
for i := 0; i < iters; i++ {
p := Generate(rs, 10, nil)
for _, call := range p.Calls {
calcChecksumsCall(call, i%32)
CalcChecksumsCall(call, i%32)
}
for try := 0; try <= 10; try++ {
p.Mutate(rs, 10, nil, nil)
for _, call := range p.Calls {
calcChecksumsCall(call, i%32)
CalcChecksumsCall(call, i%32)
}
}
}

View File

@ -1,7 +1,7 @@
// Copyright 2015 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 sys
package prog
import (
"testing"
@ -10,7 +10,7 @@ import (
func TestResourceCtors(t *testing.T) {
for _, c := range Syscalls {
for _, res := range c.InputResources() {
if len(resourceCtors(res.Desc.Kind, true)) == 0 {
if len(calcResourceCtors(res.Desc.Kind, true)) == 0 {
t.Errorf("call %v requires input resource %v, but there are no calls that can create this resource", c.Name, res.Desc.Name)
}
}

View File

@ -10,8 +10,6 @@ import (
"fmt"
"io"
"strconv"
. "github.com/google/syzkaller/sys"
)
// String generates a very compact program description (mostly for debug output).
@ -146,7 +144,7 @@ func Deserialize(data []byte) (prog *Prog, err error) {
}
c := &Call{
Meta: meta,
Ret: returnArg(meta.Ret),
Ret: MakeReturnArg(meta.Ret),
}
prog.Calls = append(prog.Calls, c)
p.Parse('(')
@ -213,13 +211,13 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
}
switch typ.(type) {
case *ConstType, *IntType, *FlagsType, *ProcType, *LenType, *CsumType:
arg = constArg(typ, v)
arg = MakeConstArg(typ, v)
case *ResourceType:
arg = resultArg(typ, nil, v)
arg = MakeResultArg(typ, nil, v)
case *PtrType:
arg = pointerArg(typ, 0, 0, 0, nil)
arg = MakePointerArg(typ, 0, 0, 0, nil)
case *VmaType:
arg = pointerArg(typ, 0, 0, 0, nil)
arg = MakePointerArg(typ, 0, 0, 0, nil)
default:
return nil, fmt.Errorf("bad const type %+v", typ)
}
@ -229,7 +227,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
if !ok || v == nil {
return nil, fmt.Errorf("result %v references unknown variable (vars=%+v)", id, vars)
}
arg = resultArg(typ, v, 0)
arg = MakeResultArg(typ, v, 0)
if p.Char() == '/' {
p.Parse('/')
op := p.Ident()
@ -267,7 +265,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
if err != nil {
return nil, err
}
arg = pointerArg(typ, page, off, size, inner)
arg = MakePointerArg(typ, page, off, size, inner)
case '(':
// This used to parse length of VmaType and return ArgPageSize, which is now removed.
// Leaving this for now for backwards compatibility.
@ -275,7 +273,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
if err != nil {
return nil, err
}
arg = constArg(typ, pages*pageSize)
arg = MakeConstArg(typ, pages*pageSize)
case '"':
p.Parse('"')
val := ""
@ -301,7 +299,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
}
fld := t1.Fields[i]
if IsPad(fld) {
inner = append(inner, constArg(fld, 0))
inner = append(inner, MakeConstArg(fld, 0))
} else {
arg, err := parseArg(fld, p, vars)
if err != nil {
@ -317,7 +315,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
for len(inner) < len(t1.Fields) {
inner = append(inner, defaultArg(t1.Fields[len(inner)]))
}
arg = groupArg(typ, inner)
arg = MakeGroupArg(typ, inner)
case '[':
t1, ok := typ.(*ArrayType)
if !ok {
@ -336,7 +334,7 @@ func parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, error) {
}
}
p.Parse(']')
arg = groupArg(typ, inner)
arg = MakeGroupArg(typ, inner)
case '@':
t1, ok := typ.(*UnionType)
if !ok {

View File

@ -1,7 +1,7 @@
// Copyright 2016 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
package prog_test
import (
"fmt"
@ -9,6 +9,9 @@ import (
"regexp"
"sort"
"testing"
. "github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
func setToArray(s map[string]struct{}) []string {
@ -76,7 +79,7 @@ func TestCallSet(t *testing.T) {
}
func TestCallSetRandom(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
for i := 0; i < iters; i++ {
p := Generate(rs, 10, nil)
calls0 := make(map[string]struct{})

View File

@ -9,8 +9,6 @@ package prog
import (
"fmt"
"sort"
. "github.com/google/syzkaller/sys"
)
const (
@ -37,9 +35,6 @@ const (
const (
ExecBufferSize = 2 << 20
pageSize = 4 << 10
dataOffset = 512 << 20
)
type Args []Arg

View File

@ -1,7 +1,7 @@
// Copyright 2016 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
package prog_test
import (
"bytes"
@ -9,13 +9,12 @@ import (
"fmt"
"testing"
. "github.com/google/syzkaller/sys"
. "github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
const ptrSize = 8
func TestSerializeForExecRandom(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
buf := make([]byte, ExecBufferSize)
for i := 0; i < iters; i++ {
p := Generate(rs, 10, nil)
@ -46,6 +45,10 @@ func TestSerializeForExec(t *testing.T) {
argResult = uint64(ExecArgResult)
argData = uint64(ExecArgData)
)
var (
dataOffset = DataOffset()
ptrSize = PtrSize()
)
callID := func(name string) uint64 {
c := SyscallMap[name]
if c == nil {

47
prog/export_test.go Normal file
View File

@ -0,0 +1,47 @@
// 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 (
"math/rand"
"testing"
"time"
)
// Export guts for testing.
func init() {
debug = true
}
var (
CalcChecksumsCall = calcChecksumsCall
AssignSizesCall = assignSizesCall
DefaultArg = defaultArg
InitTest = initTest
)
func PtrSize() uint64 {
return ptrSize
}
func DataOffset() uint64 {
return dataOffset
}
func PageSize() uint64 {
return pageSize
}
func initTest(t *testing.T) (rand.Source, int) {
t.Parallel()
iters := 10000
if testing.Short() {
iters = 100
}
seed := int64(time.Now().UnixNano())
rs := rand.NewSource(seed)
t.Logf("seed=%v", seed)
return rs, iters
}

View File

@ -20,8 +20,6 @@ package prog
import (
"encoding/binary"
. "github.com/google/syzkaller/sys"
)
type uint64Set map[uint64]bool
@ -95,7 +93,7 @@ func generateHints(p *Prog, compMap CompMap, c *Call, arg Arg, exec func(p *Prog
switch a := arg.(type) {
case *ConstArg:
originalArg = constArg(a.Type(), a.Val)
originalArg = MakeConstArg(a.Type(), a.Val)
checkConstArg(a, compMap, constArgCandidate)
case *DataArg:
originalArg = dataArg(a.Type(), a.Data)
@ -105,7 +103,7 @@ func generateHints(p *Prog, compMap CompMap, c *Call, arg Arg, exec func(p *Prog
func checkConstArg(arg *ConstArg, compMap CompMap, cb func(newArg Arg)) {
for replacer := range shrinkExpand(arg.Val, compMap) {
cb(constArg(arg.typ, replacer))
cb(MakeConstArg(arg.typ, replacer))
}
}

View File

@ -7,8 +7,6 @@ import (
"fmt"
"reflect"
"testing"
. "github.com/google/syzkaller/sys"
)
type ConstArgTest struct {

View File

@ -7,8 +7,6 @@ import (
"fmt"
"math/rand"
"unsafe"
. "github.com/google/syzkaller/sys"
)
func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Prog) {
@ -178,11 +176,11 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
arg1, calls1 := r.addr(s, t, size, a.Res)
p.replaceArg(c, arg, arg1, calls1)
case *StructType:
ctor := isSpecialStruct(t)
if ctor == nil {
gen := specialStructs[t.Name()]
if gen == nil {
panic("bad arg returned by mutationArgs: StructType")
}
arg1, calls1 := ctor(r, s)
arg1, calls1 := gen(&Gen{r, s}, t, arg.(*GroupArg))
for i, f := range arg1.(*GroupArg).Inner {
p.replaceArg(c, arg.(*GroupArg).Inner[i], f, calls1)
calls1 = nil
@ -255,7 +253,16 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
// predicate pred. It iteratively generates simpler programs and asks pred
// whether it is equal to the orginal program or not. If it is equivalent then
// the simplification attempt is committed and the process continues.
func Minimize(p0 *Prog, callIndex0 int, pred func(*Prog, int) bool, crash bool) (*Prog, int) {
func Minimize(p0 *Prog, callIndex0 int, pred0 func(*Prog, int) bool, crash bool) (*Prog, int) {
pred := pred0
if debug {
pred = func(p *Prog, callIndex int) bool {
if err := p.validate(); err != nil {
panic(err)
}
return pred0(p, callIndex)
}
}
name0 := ""
if callIndex0 != -1 {
if callIndex0 < 0 || callIndex0 >= len(p0.Calls) {
@ -291,7 +298,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred func(*Prog, int) bool, crash bool)
}
}
// Prepend uber-mmap.
mmap := createMmapCall(uint64(lo), uint64(hi-lo)+1)
mmap := makeMmap(uint64(lo), uint64(hi-lo)+1)
p.Calls = append([]*Call{mmap}, p.Calls...)
if callIndex != -1 {
callIndex++
@ -496,7 +503,7 @@ func mutationArgs(c *Call) (args, bases []Arg) {
foreachArg(c, func(arg, base Arg, _ *[]Arg) {
switch typ := arg.Type().(type) {
case *StructType:
if isSpecialStruct(typ) == nil {
if specialStructs[typ.Name()] == nil {
// For structs only individual fields are updated.
return
}
@ -524,7 +531,7 @@ func mutationArgs(c *Call) (args, bases []Arg) {
return
}
if base != nil {
if _, ok := base.Type().(*StructType); ok && isSpecialStruct(base.Type()) != nil {
if _, ok := base.Type().(*StructType); ok && specialStructs[base.Type().Name()] != nil {
// These special structs are mutated as a whole.
return
}

View File

@ -1,16 +1,19 @@
// Copyright 2015 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
package prog_test
import (
"bytes"
"fmt"
"testing"
. "github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
func TestClone(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
for i := 0; i < iters; i++ {
p := Generate(rs, 10, nil)
p1 := p.Clone()
@ -23,7 +26,7 @@ func TestClone(t *testing.T) {
}
func TestMutate(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
next:
for i := 0; i < iters; i++ {
p := Generate(rs, 10, nil)
@ -47,7 +50,7 @@ next:
}
func TestMutateCorpus(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
var corpus []*Prog
for i := 0; i < 100; i++ {
p := Generate(rs, 10, nil)
@ -137,7 +140,7 @@ func TestMutateTable(t *testing.T) {
"readv(r0, &(0x7f0000000000)=[{&(0x7f0000001000)=\"00\", 0x1}, {&(0x7f0000002000)=\"00\", 0x2}, {&(0x7f0000000000)=\"00\", 0x3}], 0x3)\n",
},
}
rs, _ := initTest(t)
rs, _ := InitTest(t)
nextTest:
for ti, test := range tests {
p, err := Deserialize([]byte(test[0]))
@ -288,35 +291,23 @@ func TestMinimize(t *testing.T) {
}
func TestMinimizeRandom(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
iters /= 10 // Long test.
for i := 0; i < iters; i++ {
p := Generate(rs, 5, nil)
Minimize(p, len(p.Calls)-1, func(p1 *Prog, callIndex int) bool {
if err := p1.validate(); err != nil {
t.Fatalf("invalid program: %v", err)
}
return false
}, true)
Minimize(p, len(p.Calls)-1, func(p1 *Prog, callIndex int) bool {
if err := p1.validate(); err != nil {
t.Fatalf("invalid program: %v", err)
}
return true
}, true)
}
for i := 0; i < iters; i++ {
p := Generate(rs, 5, nil)
Minimize(p, len(p.Calls)-1, func(p1 *Prog, callIndex int) bool {
if err := p1.validate(); err != nil {
t.Fatalf("invalid program: %v", err)
}
return false
}, false)
Minimize(p, len(p.Calls)-1, func(p1 *Prog, callIndex int) bool {
if err := p1.validate(); err != nil {
t.Fatalf("invalid program: %v", err)
}
return true
}, false)
}

View File

@ -7,8 +7,6 @@ import (
"fmt"
"math/rand"
"sort"
. "github.com/google/syzkaller/sys"
)
// Calulation of call-to-call priorities.

View File

@ -5,8 +5,6 @@ package prog
import (
"fmt"
. "github.com/google/syzkaller/sys"
)
type Prog struct {
@ -224,11 +222,11 @@ func encodeValue(value uint64, size uint64, bigEndian bool) uint64 {
}
}
func constArg(t Type, v uint64) Arg {
func MakeConstArg(t Type, v uint64) Arg {
return &ConstArg{ArgCommon: ArgCommon{typ: t}, Val: v}
}
func resultArg(t Type, r Arg, v uint64) Arg {
func MakeResultArg(t Type, r Arg, v uint64) Arg {
arg := &ResultArg{ArgCommon: ArgCommon{typ: t}, Res: r, Val: v}
if r == nil {
return arg
@ -249,11 +247,11 @@ func dataArg(t Type, data []byte) Arg {
return &DataArg{ArgCommon: ArgCommon{typ: t}, Data: append([]byte{}, data...)}
}
func pointerArg(t Type, page uint64, off int, npages uint64, obj Arg) Arg {
func MakePointerArg(t Type, page uint64, off int, npages uint64, obj Arg) Arg {
return &PointerArg{ArgCommon: ArgCommon{typ: t}, PageIndex: page, PageOffset: off, PagesNum: npages, Res: obj}
}
func groupArg(t Type, inner []Arg) Arg {
func MakeGroupArg(t Type, inner []Arg) Arg {
return &GroupArg{ArgCommon: ArgCommon{typ: t}, Inner: inner}
}
@ -261,16 +259,16 @@ func unionArg(t Type, opt Arg, typ Type) Arg {
return &UnionArg{ArgCommon: ArgCommon{typ: t}, Option: opt, OptionType: typ}
}
func returnArg(t Type) Arg {
func MakeReturnArg(t Type) Arg {
return &ReturnArg{ArgCommon: ArgCommon{typ: t}}
}
func defaultArg(t Type) Arg {
switch typ := t.(type) {
case *IntType, *ConstType, *FlagsType, *LenType, *ProcType, *CsumType:
return constArg(t, t.Default())
return MakeConstArg(t, t.Default())
case *ResourceType:
return resultArg(t, nil, typ.Desc.Type.Default())
return MakeResultArg(t, nil, typ.Desc.Type.Default())
case *BufferType:
var data []byte
if typ.Kind == BufferString && typ.TypeSize != 0 {
@ -278,23 +276,23 @@ func defaultArg(t Type) Arg {
}
return dataArg(t, data)
case *ArrayType:
return groupArg(t, nil)
return MakeGroupArg(t, nil)
case *StructType:
var inner []Arg
for _, field := range typ.Fields {
inner = append(inner, defaultArg(field))
}
return groupArg(t, inner)
return MakeGroupArg(t, inner)
case *UnionType:
return unionArg(t, defaultArg(typ.Fields[0]), typ.Fields[0])
case *VmaType:
return pointerArg(t, 0, 0, 1, nil)
return MakePointerArg(t, 0, 0, 1, nil)
case *PtrType:
var res Arg
if !t.Optional() && t.Dir() != DirOut {
res = defaultArg(typ.Type)
}
return pointerArg(t, 0, 0, 0, res)
return MakePointerArg(t, 0, 0, 0, res)
default:
panic("unknown arg type")
}
@ -364,7 +362,7 @@ func (p *Prog) removeArg(c *Call, arg0 Arg) {
if _, ok := arg1.(*ResultArg); !ok {
panic("use references not ArgResult")
}
arg2 := resultArg(arg1.Type(), nil, arg1.Type().Default())
arg2 := MakeResultArg(arg1.Type(), nil, arg1.Type().Default())
p.replaceArg(c, arg1, arg2, nil)
}
}

View File

@ -6,47 +6,29 @@ package prog
import (
"bytes"
"fmt"
"math/rand"
"testing"
"time"
. "github.com/google/syzkaller/sys"
//. "github.com/google/syzkaller/prog"
//_ "github.com/google/syzkaller/sys"
)
func init() {
debug = true
}
func initTest(t *testing.T) (rand.Source, int) {
t.Parallel()
iters := 10000
if testing.Short() {
iters = 100
}
seed := int64(time.Now().UnixNano())
rs := rand.NewSource(seed)
t.Logf("seed=%v", seed)
return rs, iters
}
func TestGeneration(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
for i := 0; i < iters; i++ {
Generate(rs, 20, nil)
}
}
func TestDefault(t *testing.T) {
initTest(t)
InitTest(t)
for _, meta := range SyscallMap {
for _, t := range meta.Args {
defaultArg(t)
DefaultArg(t)
}
}
}
func TestDefaultCallArgs(t *testing.T) {
initTest(t)
InitTest(t)
for _, meta := range SyscallMap {
// Ensure that we can restore all arguments of all calls.
prog := fmt.Sprintf("%v()", meta.Name)
@ -61,7 +43,7 @@ func TestDefaultCallArgs(t *testing.T) {
}
func TestSerialize(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
for i := 0; i < iters; i++ {
p := Generate(rs, 10, nil)
data := p.Serialize()
@ -83,9 +65,10 @@ func TestSerialize(t *testing.T) {
}
func TestVmaType(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
meta := SyscallMap["syz_test$vma0"]
r := newRand(rs)
pageSize := PageSize()
for i := 0; i < iters; i++ {
s := newState(nil)
calls := r.generateParticularCall(s, meta)

View File

@ -12,7 +12,6 @@ import (
"sync"
"github.com/google/syzkaller/pkg/ifuzz"
. "github.com/google/syzkaller/sys"
)
var pageStartPool = sync.Pool{New: func() interface{} { return new([]uint64) }}
@ -224,102 +223,6 @@ func (r *randGen) randStringImpl(s *state, vals []string) []byte {
return buf.Bytes()
}
func isSpecialStruct(typ Type) func(r *randGen, s *state) (Arg, []*Call) {
a, ok := typ.(*StructType)
if !ok {
panic("must be a struct")
}
switch typ.Name() {
case "timespec":
return func(r *randGen, s *state) (Arg, []*Call) {
return r.timespec(s, a, false)
}
case "timeval":
return func(r *randGen, s *state) (Arg, []*Call) {
return r.timespec(s, a, true)
}
}
return nil
}
func (r *randGen) timespec(s *state, typ *StructType, usec bool) (arg Arg, calls []*Call) {
// We need to generate timespec/timeval that are either (1) definitely in the past,
// or (2) definitely in unreachable fututre, or (3) few ms ahead of now.
// Note timespec/timeval can be absolute or relative to now.
switch {
case r.nOutOf(1, 4):
// now for relative, past for absolute
arg = groupArg(typ, []Arg{
resultArg(typ.Fields[0], nil, 0),
resultArg(typ.Fields[1], nil, 0),
})
case r.nOutOf(1, 3):
// few ms ahead for relative, past for absolute
nsec := uint64(10 * 1e6)
if usec {
nsec /= 1e3
}
arg = groupArg(typ, []Arg{
resultArg(typ.Fields[0], nil, 0),
resultArg(typ.Fields[1], nil, nsec),
})
case r.nOutOf(1, 2):
// unreachable fututre for both relative and absolute
arg = groupArg(typ, []Arg{
resultArg(typ.Fields[0], nil, 2e9),
resultArg(typ.Fields[1], nil, 0),
})
default:
// few ms ahead for absolute
meta := SyscallMap["clock_gettime"]
ptrArgType := meta.Args[1].(*PtrType)
argType := ptrArgType.Type.(*StructType)
tp := groupArg(argType, []Arg{
resultArg(argType.Fields[0], nil, 0),
resultArg(argType.Fields[1], nil, 0),
})
var tpaddr Arg
tpaddr, calls = r.addr(s, ptrArgType, 16, tp)
gettime := &Call{
Meta: meta,
Args: []Arg{
constArg(meta.Args[0], CLOCK_REALTIME),
tpaddr,
},
Ret: returnArg(meta.Ret),
}
calls = append(calls, gettime)
sec := resultArg(typ.Fields[0], tp.(*GroupArg).Inner[0], 0)
nsec := resultArg(typ.Fields[1], tp.(*GroupArg).Inner[1], 0)
if usec {
nsec.(*ResultArg).OpDiv = 1e3
nsec.(*ResultArg).OpAdd = 10 * 1e3
} else {
nsec.(*ResultArg).OpAdd = 10 * 1e6
}
arg = groupArg(typ, []Arg{sec, nsec})
}
return
}
// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range.
func createMmapCall(start, npages uint64) *Call {
meta := SyscallMap["mmap"]
mmap := &Call{
Meta: meta,
Args: []Arg{
pointerArg(meta.Args[0], start, 0, npages, nil),
constArg(meta.Args[1], npages*pageSize),
constArg(meta.Args[2], PROT_READ|PROT_WRITE),
constArg(meta.Args[3], MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED),
resultArg(meta.Args[4], nil, InvalidFD),
constArg(meta.Args[5], 0),
},
Ret: returnArg(meta.Ret),
}
return mmap
}
func (r *randGen) addr1(s *state, typ Type, size uint64, data Arg) (Arg, []*Call) {
npages := (size + pageSize - 1) / pageSize
if npages == 0 {
@ -339,8 +242,8 @@ func (r *randGen) addr1(s *state, typ Type, size uint64, data Arg) (Arg, []*Call
if !free {
continue
}
c := createMmapCall(i, npages)
return pointerArg(typ, i, 0, 0, data), []*Call{c}
c := makeMmap(i, npages)
return MakePointerArg(typ, i, 0, 0, data), []*Call{c}
}
return r.randPageAddr(s, typ, npages, data, false), nil
}
@ -357,7 +260,7 @@ func (r *randGen) addr(s *state, typ Type, size uint64, data Arg) (Arg, []*Call)
case r.nOutOf(50, 52):
a.PageOffset = -int(size)
case r.nOutOf(1, 2):
a.PageOffset = r.Intn(pageSize)
a.PageOffset = r.Intn(int(pageSize))
default:
if size > 0 {
a.PageOffset = -r.Intn(int(size))
@ -395,13 +298,13 @@ func (r *randGen) randPageAddr(s *state, typ Type, npages uint64, data Arg, vma
}
*poolPtr = starts
pageStartPool.Put(poolPtr)
return pointerArg(typ, page, 0, npages, data)
return MakePointerArg(typ, page, 0, npages, data)
}
func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls []*Call) {
if r.inCreateResource {
special := res.SpecialValues()
return resultArg(res, nil, special[r.Intn(len(special))]), nil
return MakeResultArg(res, nil, special[r.Intn(len(special))]), nil
}
r.inCreateResource = true
defer func() { r.inCreateResource = false }()
@ -428,7 +331,7 @@ func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls []
metas = append(metas, meta)
}
if len(metas) == 0 {
return resultArg(res, nil, res.Default()), nil
return MakeResultArg(res, nil, res.Default()), nil
}
// Now we have a set of candidate calls that can create the necessary resource.
@ -447,7 +350,7 @@ func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls []
}
if len(allres) != 0 {
// Bingo!
arg := resultArg(res, allres[r.Intn(len(allres))], 0)
arg := MakeResultArg(res, allres[r.Intn(len(allres))], 0)
return arg, calls
}
// Discard unsuccessful calls.
@ -550,7 +453,7 @@ func (r *randGen) generateCall(s *state, p *Prog) []*Call {
func (r *randGen) generateParticularCall(s *state, meta *Syscall) (calls []*Call) {
c := &Call{
Meta: meta,
Ret: returnArg(meta.Ret),
Ret: MakeReturnArg(meta.Ret),
}
c.Args, calls = r.generateArgs(s, meta.Args)
assignSizesCall(c)
@ -629,7 +532,7 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
}
}()
if r.recDepth[str.Name()] >= 3 {
return pointerArg(typ, 0, 0, 0, nil), nil
return MakePointerArg(typ, 0, 0, 0, nil), nil
}
}
}
@ -650,7 +553,7 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
}
}
if len(allres) != 0 {
arg = resultArg(a, allres[r.Intn(len(allres))], 0)
arg = MakeResultArg(a, allres[r.Intn(len(allres))], 0)
} else {
arg, calls = r.createResource(s, a)
}
@ -659,7 +562,7 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
arg, calls = r.createResource(s, a)
default:
special := a.SpecialValues()
arg = resultArg(a, nil, special[r.Intn(len(special))])
arg = MakeResultArg(a, nil, special[r.Intn(len(special))])
}
return arg, calls
case *BufferType:
@ -707,9 +610,9 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
arg := r.randPageAddr(s, a, npages, nil, true)
return arg, nil
case *FlagsType:
return constArg(a, r.flags(a.Vals)), nil
return MakeConstArg(a, r.flags(a.Vals)), nil
case *ConstType:
return constArg(a, a.Val), nil
return MakeConstArg(a, a.Val), nil
case *IntType:
v := r.randInt()
switch a.Kind {
@ -725,9 +628,9 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
case IntRange:
v = r.randRangeInt(a.RangeBegin, a.RangeEnd)
}
return constArg(a, v), nil
return MakeConstArg(a, v), nil
case *ProcType:
return constArg(a, r.rand(int(a.ValuesPerProc))), nil
return MakeConstArg(a, r.rand(int(a.ValuesPerProc))), nil
case *ArrayType:
var count uint64
switch a.Kind {
@ -743,14 +646,14 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
inner = append(inner, arg1)
calls = append(calls, calls1...)
}
return groupArg(a, inner), calls
return MakeGroupArg(a, inner), calls
case *StructType:
if ctor := isSpecialStruct(a); ctor != nil && a.Dir() != DirOut {
arg, calls = ctor(r, s)
if gen := specialStructs[a.Name()]; gen != nil && a.Dir() != DirOut {
arg, calls = gen(&Gen{r, s}, a, nil)
return
}
args, calls := r.generateArgs(s, a.Fields)
group := groupArg(a, args)
group := MakeGroupArg(a, args)
return group, calls
case *UnionType:
optType := a.Fields[r.Intn(len(a.Fields))]
@ -763,7 +666,7 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
// So try to reuse a previously used address.
addrs := s.resources["iocbptr"]
addr := addrs[r.Intn(len(addrs))].(*PointerArg)
arg = pointerArg(a, addr.PageIndex, addr.PageOffset, addr.PagesNum, inner)
arg = MakePointerArg(a, addr.PageIndex, addr.PageOffset, addr.PagesNum, inner)
return arg, calls
}
arg, calls1 := r.addr(s, a, inner.Size(), inner)
@ -771,9 +674,9 @@ func (r *randGen) generateArg(s *state, typ Type) (arg Arg, calls []*Call) {
return arg, calls
case *LenType:
// Return placeholder value of 0 while generating len arg.
return constArg(a, 0), nil
return MakeConstArg(a, 0), nil
case *CsumType:
return constArg(a, 0), nil
return MakeConstArg(a, 0), nil
default:
panic("unknown argument type")
}

View File

@ -5,32 +5,30 @@ package prog
import (
"fmt"
. "github.com/google/syzkaller/sys"
)
func generateSize(arg Arg, lenType *LenType) Arg {
if arg == nil {
// Arg is an optional pointer, set size to 0.
return constArg(lenType, 0)
return MakeConstArg(lenType, 0)
}
switch arg.Type().(type) {
case *VmaType:
a := arg.(*PointerArg)
return constArg(lenType, a.PagesNum*pageSize)
return MakeConstArg(lenType, a.PagesNum*pageSize)
case *ArrayType:
a := arg.(*GroupArg)
if lenType.ByteSize != 0 {
return constArg(lenType, a.Size()/lenType.ByteSize)
return MakeConstArg(lenType, a.Size()/lenType.ByteSize)
} else {
return constArg(lenType, uint64(len(a.Inner)))
return MakeConstArg(lenType, uint64(len(a.Inner)))
}
default:
if lenType.ByteSize != 0 {
return constArg(lenType, arg.Size()/lenType.ByteSize)
return MakeConstArg(lenType, arg.Size()/lenType.ByteSize)
} else {
return constArg(lenType, arg.Size())
return MakeConstArg(lenType, arg.Size())
}
}
}

View File

@ -1,21 +1,24 @@
// Copyright 2016 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
package prog_test
import (
"bytes"
"strings"
"testing"
. "github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
func TestAssignSizeRandom(t *testing.T) {
rs, iters := initTest(t)
rs, iters := InitTest(t)
for i := 0; i < iters; i++ {
p := Generate(rs, 10, nil)
data0 := p.Serialize()
for _, call := range p.Calls {
assignSizesCall(call)
AssignSizesCall(call)
}
if data1 := p.Serialize(); !bytes.Equal(data0, data1) {
t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1)
@ -23,7 +26,7 @@ func TestAssignSizeRandom(t *testing.T) {
p.Mutate(rs, 10, nil, nil)
data0 = p.Serialize()
for _, call := range p.Calls {
assignSizesCall(call)
AssignSizesCall(call)
}
if data1 := p.Serialize(); !bytes.Equal(data0, data1) {
t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1)
@ -128,7 +131,7 @@ func TestAssignSize(t *testing.T) {
t.Fatalf("failed to deserialize prog %v: %v", i, err)
}
for _, call := range p.Calls {
assignSizesCall(call)
AssignSizesCall(call)
}
p1 := strings.TrimSpace(string(p.Serialize()))
if p1 != test.sizedProg {

117
prog/target.go Normal file
View File

@ -0,0 +1,117 @@
// 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"
)
// Target describes target OS/arch pair.
type Target struct {
OS string
Arch string
PtrSize uint64
PageSize uint64
DataOffset uint64
Syscalls []*Syscall
Resources []*ResourceDesc
// 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)
resourceMap map[string]*ResourceDesc
syscallMap map[string]*Syscall
resourceCtors map[string][]*Syscall
}
type StructGen func(g *Gen, typ *StructType, old *GroupArg) (Arg, []*Call)
var targets = make(map[string]*Target)
func RegisterTarget(target *Target) {
key := target.OS + "/" + target.Arch
if targets[key] != nil {
panic(fmt.Sprintf("duplicate target %v", key))
}
initTarget(target)
targets[key] = target
// For now we copy target to global vars
// because majority of the code is not prepared for multiple targets.
if len(targets) > 1 {
panic("only 1 target is supported")
}
Syscalls = target.Syscalls
SyscallMap = target.syscallMap
Resources = target.resourceMap
resourceCtors = target.resourceCtors
ptrSize = target.PtrSize
pageSize = target.PageSize
dataOffset = target.DataOffset
makeMmap = target.MakeMmap
analyzeMmap = target.AnalyzeMmap
sanitizeCall = target.SanitizeCall
specialStructs = target.SpecialStructs
}
func initTarget(target *Target) {
target.syscallMap = make(map[string]*Syscall)
for _, c := range target.Syscalls {
target.syscallMap[c.Name] = c
}
target.resourceMap = make(map[string]*ResourceDesc)
target.resourceCtors = make(map[string][]*Syscall)
for _, r := range target.Resources {
target.resourceMap[r.Name] = r
target.resourceCtors[r.Name] = calcResourceCtors(r.Kind, false)
}
}
type Gen struct {
r *randGen
s *state
}
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)
}
var (
ptrSize uint64
pageSize uint64
dataOffset uint64
Syscalls []*Syscall
SyscallMap map[string]*Syscall
Resources map[string]*ResourceDesc
resourceCtors map[string][]*Syscall
makeMmap func(start, npages uint64) *Call
analyzeMmap func(c *Call) (start, npages uint64, mapped bool)
sanitizeCall func(c *Call)
specialStructs map[string]func(g *Gen, typ *StructType, old *GroupArg) (Arg, []*Call)
)

View File

@ -1,7 +1,7 @@
// Copyright 2015/2016 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 sys
package prog
import (
"fmt"
@ -95,10 +95,6 @@ func (t TypeCommon) Dir() Dir {
return t.ArgDir
}
const (
InvalidFD = ^uint64(0)
)
type ResourceDesc struct {
Name string
Type Type
@ -267,12 +263,6 @@ func (t *UnionType) FieldName() string {
return t.FldName
}
var (
SyscallMap = make(map[string]*Syscall)
Resources map[string]*ResourceDesc
ctors = make(map[string][]*Syscall)
)
type StructDesc struct {
TypeCommon
Fields []Type
@ -293,53 +283,12 @@ type KeyedStruct struct {
Desc *StructDesc
}
func initStructFields() {
keyedStructs := make(map[StructKey]*StructDesc)
for _, desc := range structDescs {
keyedStructs[desc.Key] = desc.Desc
}
for _, c := range Syscalls {
ForeachType(c, func(t Type) {
switch s := t.(type) {
case *StructType:
s.StructDesc = keyedStructs[s.Key]
if s.StructDesc == nil {
panic("no struct desc")
}
case *UnionType:
s.StructDesc = keyedStructs[s.Key]
if s.StructDesc == nil {
panic("no union desc")
}
}
})
}
}
// ResourceConstructors returns a list of calls that can create a resource of the given kind.
func ResourceConstructors(name string) []*Syscall {
return ctors[name]
return resourceCtors[name]
}
func initResources() {
Resources = make(map[string]*ResourceDesc)
for _, res := range resourceArray {
Resources[res.Name] = res
}
for _, c := range Syscalls {
ForeachType(c, func(t Type) {
if r, ok := t.(*ResourceType); ok {
r.Desc = Resources[r.TypeName]
}
})
}
for _, res := range resourceArray {
ctors[res.Name] = resourceCtors(res.Kind, false)
}
}
func resourceCtors(kind []string, precise bool) []*Syscall {
func calcResourceCtors(kind []string, precise bool) []*Syscall {
// Find calls that produce the necessary resources.
var metas []*Syscall
for _, meta := range Syscalls {
@ -426,7 +375,7 @@ func TransitivelyEnabledCalls(enabled map[*Syscall]bool) map[*Syscall]bool {
if _, ok := ctors[res.Desc.Name]; ok {
continue
}
ctors[res.Desc.Name] = resourceCtors(res.Desc.Kind, true)
ctors[res.Desc.Name] = calcResourceCtors(res.Desc.Kind, true)
}
}
for {
@ -506,17 +455,3 @@ func ForeachType(meta *Syscall, f func(Type)) {
rec(meta.Ret)
}
}
func init() {
initStructFields()
initResources()
structDescs = nil
for _, c := range Syscalls {
if SyscallMap[c.Name] != nil {
println(c.Name)
panic("duplicate syscall")
}
SyscallMap[c.Name] = c
}
}

View File

@ -5,8 +5,6 @@ package prog
import (
"fmt"
. "github.com/google/syzkaller/sys"
)
var debug = false // enabled in tests

257
sys/init.go Normal file
View File

@ -0,0 +1,257 @@
// 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 sys
import (
"runtime"
"github.com/google/syzkaller/prog"
)
func init() {
lazyInit()
target := &prog.Target{
OS: runtime.GOOS,
Arch: runtime.GOARCH,
PtrSize: ptrSize,
PageSize: pageSize,
DataOffset: dataOffset,
Syscalls: syscalls,
Resources: resources,
MakeMmap: makeMmap,
AnalyzeMmap: analyzeMmap,
SanitizeCall: sanitizeCall,
SpecialStructs: map[string]func(g *prog.Gen, typ *prog.StructType, old *prog.GroupArg) (prog.Arg, []*prog.Call){
"timespec": generateTimespec,
"timeval": generateTimespec,
},
}
prog.RegisterTarget(target)
}
const (
// TODO(dvyukov): dehardcode
ptrSize = 8
pageSize = 4 << 10
dataOffset = 512 << 20
invalidFD = ^uint64(0)
)
var (
mmapSyscall *prog.Syscall
clockGettimeSyscall *prog.Syscall
)
// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range.
func makeMmap(start, npages uint64) *prog.Call {
return &prog.Call{
Meta: mmapSyscall,
Args: []prog.Arg{
prog.MakePointerArg(mmapSyscall.Args[0], start, 0, npages, nil),
prog.MakeConstArg(mmapSyscall.Args[1], npages*pageSize),
prog.MakeConstArg(mmapSyscall.Args[2], PROT_READ|PROT_WRITE),
prog.MakeConstArg(mmapSyscall.Args[3], MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED),
prog.MakeResultArg(mmapSyscall.Args[4], nil, invalidFD),
prog.MakeConstArg(mmapSyscall.Args[5], 0),
},
Ret: prog.MakeReturnArg(mmapSyscall.Ret),
}
}
func analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) {
switch c.Meta.Name {
case "mmap":
// Filter out only very wrong arguments.
npages = c.Args[1].(*prog.ConstArg).Val / pageSize
if npages == 0 {
return
}
flags := c.Args[3].(*prog.ConstArg).Val
fd := c.Args[4].(*prog.ResultArg).Val
if flags&MAP_ANONYMOUS == 0 && fd == invalidFD {
return
}
start = c.Args[0].(*prog.PointerArg).PageIndex
mapped = true
return
case "munmap":
start = c.Args[0].(*prog.PointerArg).PageIndex
npages = c.Args[1].(*prog.ConstArg).Val / pageSize
mapped = false
return
case "mremap":
start = c.Args[4].(*prog.PointerArg).PageIndex
npages = c.Args[2].(*prog.ConstArg).Val / pageSize
mapped = true
return
default:
return
}
}
func sanitizeCall(c *prog.Call) {
switch c.Meta.CallName {
case "mmap":
// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
c.Args[3].(*prog.ConstArg).Val |= MAP_FIXED
case "mremap":
// Add MREMAP_FIXED flag, otherwise it produces non-deterministic results.
flags := c.Args[3].(*prog.ConstArg)
if flags.Val&MREMAP_MAYMOVE != 0 {
flags.Val |= MREMAP_FIXED
}
case "mknod", "mknodat":
pos := 1
if c.Meta.CallName == "mknodat" {
pos = 2
}
mode := c.Args[pos].(*prog.ConstArg)
dev := c.Args[pos+1].(*prog.ConstArg)
// Char and block devices read/write io ports, kernel memory and do other nasty things.
// TODO: not required if executor drops privileges.
switch mode.Val & (S_IFREG | S_IFCHR | S_IFBLK | S_IFIFO | S_IFSOCK) {
case S_IFREG, S_IFIFO, S_IFSOCK:
case S_IFBLK:
if dev.Val>>8 == 7 {
break // loop
}
mode.Val &^= S_IFBLK
mode.Val |= S_IFREG
case S_IFCHR:
mode.Val &^= S_IFCHR
mode.Val |= S_IFREG
}
case "syslog":
cmd := c.Args[0].(*prog.ConstArg)
// These disable console output, but we need it.
if cmd.Val == SYSLOG_ACTION_CONSOLE_OFF || cmd.Val == SYSLOG_ACTION_CONSOLE_ON {
cmd.Val = SYSLOG_ACTION_SIZE_UNREAD
}
case "ioctl":
cmd := c.Args[1].(*prog.ConstArg)
// Freeze kills machine. Though, it is an interesting functions,
// so we need to test it somehow.
// TODO: not required if executor drops privileges.
if uint32(cmd.Val) == FIFREEZE {
cmd.Val = FITHAW
}
case "ptrace":
req := c.Args[0].(*prog.ConstArg)
// PTRACE_TRACEME leads to unkillable processes, see:
// https://groups.google.com/forum/#!topic/syzkaller/uGzwvhlCXAw
if req.Val == PTRACE_TRACEME {
req.Val = ^uint64(0)
}
case "exit", "exit_group":
code := c.Args[0].(*prog.ConstArg)
// These codes are reserved by executor.
if code.Val%128 == 67 || code.Val%128 == 68 {
code.Val = 1
}
}
}
func generateTimespec(g *prog.Gen, typ *prog.StructType, old *prog.GroupArg) (arg prog.Arg, calls []*prog.Call) {
// We need to generate timespec/timeval that are either
// (1) definitely in the past, or
// (2) definitely in unreachable fututre, or
// (3) few ms ahead of now.
// Note timespec/timeval can be absolute or relative to now.
usec := typ.Name() == "timeval"
switch {
case g.NOutOf(1, 4):
// Now for relative, past for absolute.
arg = prog.MakeGroupArg(typ, []prog.Arg{
prog.MakeResultArg(typ.Fields[0], nil, 0),
prog.MakeResultArg(typ.Fields[1], nil, 0),
})
case g.NOutOf(1, 3):
// Few ms ahead for relative, past for absolute
nsec := uint64(10 * 1e6)
if usec {
nsec /= 1e3
}
arg = prog.MakeGroupArg(typ, []prog.Arg{
prog.MakeResultArg(typ.Fields[0], nil, 0),
prog.MakeResultArg(typ.Fields[1], nil, nsec),
})
case g.NOutOf(1, 2):
// Unreachable fututre for both relative and absolute
arg = prog.MakeGroupArg(typ, []prog.Arg{
prog.MakeResultArg(typ.Fields[0], nil, 2e9),
prog.MakeResultArg(typ.Fields[1], nil, 0),
})
default:
// Few ms ahead for absolute.
meta := clockGettimeSyscall
ptrArgType := meta.Args[1].(*prog.PtrType)
argType := ptrArgType.Type.(*prog.StructType)
tp := prog.MakeGroupArg(argType, []prog.Arg{
prog.MakeResultArg(argType.Fields[0], nil, 0),
prog.MakeResultArg(argType.Fields[1], nil, 0),
})
var tpaddr prog.Arg
tpaddr, calls = g.Alloc(ptrArgType, tp)
gettime := &prog.Call{
Meta: meta,
Args: []prog.Arg{
prog.MakeConstArg(meta.Args[0], CLOCK_REALTIME),
tpaddr,
},
Ret: prog.MakeReturnArg(meta.Ret),
}
calls = append(calls, gettime)
sec := prog.MakeResultArg(typ.Fields[0], tp.(*prog.GroupArg).Inner[0], 0)
nsec := prog.MakeResultArg(typ.Fields[1], tp.(*prog.GroupArg).Inner[1], 0)
if usec {
nsec.(*prog.ResultArg).OpDiv = 1e3
nsec.(*prog.ResultArg).OpAdd = 10 * 1e3
} else {
nsec.(*prog.ResultArg).OpAdd = 10 * 1e6
}
arg = prog.MakeGroupArg(typ, []prog.Arg{sec, nsec})
}
return
}
func lazyInit() {
resourceMap := make(map[string]*prog.ResourceDesc)
for _, res := range resources {
resourceMap[res.Name] = res
}
keyedStructs := make(map[prog.StructKey]*prog.StructDesc)
for _, desc := range structDescs {
keyedStructs[desc.Key] = desc.Desc
}
structDescs = nil
for _, c := range syscalls {
prog.ForeachType(c, func(t0 prog.Type) {
switch t := t0.(type) {
case *prog.ResourceType:
t.Desc = resourceMap[t.TypeName]
if t.Desc == nil {
panic("no resource desc")
}
case *prog.StructType:
t.StructDesc = keyedStructs[t.Key]
if t.StructDesc == nil {
panic("no struct desc")
}
case *prog.UnionType:
t.StructDesc = keyedStructs[t.Key]
if t.StructDesc == nil {
panic("no union desc")
}
}
})
switch c.Name {
case "mmap":
mmapSyscall = c
case "clock_gettime":
clockGettimeSyscall = c
}
}
}

View File

@ -1,7 +1,9 @@
// AUTOGENERATED FILE
package sys
var resourceArray = []*ResourceDesc{
import . "github.com/google/syzkaller/prog"
var resources = []*ResourceDesc{
{Name: "assoc_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"assoc_id"}, Values: []uint64{0}},
{Name: "bpf_map_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_map_id"}, Values: []uint64{0, 4294967295}},
{Name: "bpf_prog_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_prog_id"}, Values: []uint64{0, 4294967295}},
@ -5892,7 +5894,7 @@ var structDescs = []*KeyedStruct{
}}},
}
var Syscalls = []*Syscall{
var syscalls = []*Syscall{
{NR: 18446744073709551615, Name: "accept", CallName: "accept", Args: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "sock", FldName: "fd", TypeSize: 4}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "peer", TypeSize: 4, IsOptional: true}, Type: &UnionType{Key: StructKey{Name: "sockaddr_storage", Dir: 1}}},

View File

@ -1,7 +1,9 @@
// AUTOGENERATED FILE
package sys
var resourceArray = []*ResourceDesc{
import . "github.com/google/syzkaller/prog"
var resources = []*ResourceDesc{
{Name: "assoc_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"assoc_id"}, Values: []uint64{0}},
{Name: "bpf_map_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_map_id"}, Values: []uint64{0, 4294967295}},
{Name: "bpf_prog_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_prog_id"}, Values: []uint64{0, 4294967295}},
@ -5941,7 +5943,7 @@ var structDescs = []*KeyedStruct{
}}},
}
var Syscalls = []*Syscall{
var syscalls = []*Syscall{
{NR: 43, Name: "accept", CallName: "accept", Args: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "sock", FldName: "fd", TypeSize: 4}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "peer", TypeSize: 8, IsOptional: true}, Type: &UnionType{Key: StructKey{Name: "sockaddr_storage", Dir: 1}}},

View File

@ -1,7 +1,9 @@
// AUTOGENERATED FILE
package sys
var resourceArray = []*ResourceDesc{
import . "github.com/google/syzkaller/prog"
var resources = []*ResourceDesc{
{Name: "assoc_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"assoc_id"}, Values: []uint64{0}},
{Name: "bpf_map_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_map_id"}, Values: []uint64{0, 4294967295}},
{Name: "bpf_prog_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_prog_id"}, Values: []uint64{0, 4294967295}},
@ -5892,7 +5894,7 @@ var structDescs = []*KeyedStruct{
}}},
}
var Syscalls = []*Syscall{
var syscalls = []*Syscall{
{NR: 9437469, Name: "accept", CallName: "accept", Args: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "sock", FldName: "fd", TypeSize: 4}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "peer", TypeSize: 4, IsOptional: true}, Type: &UnionType{Key: StructKey{Name: "sockaddr_storage", Dir: 1}}},

View File

@ -1,7 +1,9 @@
// AUTOGENERATED FILE
package sys
var resourceArray = []*ResourceDesc{
import . "github.com/google/syzkaller/prog"
var resources = []*ResourceDesc{
{Name: "assoc_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"assoc_id"}, Values: []uint64{0}},
{Name: "bpf_map_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_map_id"}, Values: []uint64{0, 4294967295}},
{Name: "bpf_prog_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_prog_id"}, Values: []uint64{0, 4294967295}},
@ -5941,7 +5943,7 @@ var structDescs = []*KeyedStruct{
}}},
}
var Syscalls = []*Syscall{
var syscalls = []*Syscall{
{NR: 202, Name: "accept", CallName: "accept", Args: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "sock", FldName: "fd", TypeSize: 4}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "peer", TypeSize: 8, IsOptional: true}, Type: &UnionType{Key: StructKey{Name: "sockaddr_storage", Dir: 1}}},

View File

@ -1,7 +1,9 @@
// AUTOGENERATED FILE
package sys
var resourceArray = []*ResourceDesc{
import . "github.com/google/syzkaller/prog"
var resources = []*ResourceDesc{
{Name: "assoc_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"assoc_id"}, Values: []uint64{0}},
{Name: "bpf_map_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_map_id"}, Values: []uint64{0, 4294967295}},
{Name: "bpf_prog_id", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"bpf_prog_id"}, Values: []uint64{0, 4294967295}},
@ -5941,7 +5943,7 @@ var structDescs = []*KeyedStruct{
}}},
}
var Syscalls = []*Syscall{
var syscalls = []*Syscall{
{NR: 330, Name: "accept", CallName: "accept", Args: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "sock", FldName: "fd", TypeSize: 4}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "peer", TypeSize: 8, IsOptional: true}, Type: &UnionType{Key: StructKey{Name: "sockaddr_storage", Dir: 1}}},

View File

@ -9,7 +9,7 @@ import (
"strings"
"text/template"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/prog"
)
type Arch struct {
@ -26,7 +26,7 @@ var archs = []*Arch{
{"ppc64le", 8, []string{"__ppc64__", "__PPC64__", "__powerpc64__"}},
}
func generateExecutorSyscalls(arch *Arch, syscalls []*sys.Syscall) []byte {
func generateExecutorSyscalls(arch *Arch, syscalls []*prog.Syscall) []byte {
data := ArchData{
CARCH: arch.CARCH,
}

View File

@ -116,8 +116,9 @@ func main() {
func generate(arch string, prog *compiler.Prog, consts map[string]uint64, out io.Writer) {
fmt.Fprintf(out, "// AUTOGENERATED FILE\n")
fmt.Fprintf(out, "package sys\n\n")
fmt.Fprintf(out, "import . \"github.com/google/syzkaller/prog\"\n\n")
fmt.Fprintf(out, "var resourceArray = ")
fmt.Fprintf(out, "var resources = ")
serializer.Write(out, prog.Resources)
fmt.Fprintf(out, "\n\n")
@ -133,7 +134,7 @@ func generate(arch string, prog *compiler.Prog, consts map[string]uint64, out io
serializer.Write(out, prog.StructDescs)
fmt.Fprintf(out, "\n\n")
fmt.Fprintf(out, "var Syscalls = ")
fmt.Fprintf(out, "var syscalls = ")
serializer.Write(out, prog.Syscalls)
fmt.Fprintf(out, "\n\n")

View File

@ -202,10 +202,10 @@ func main() {
if err != nil {
panic(err)
}
if _, ok := calls[sys.SyscallMap["syz_emit_ethernet"]]; ok {
if _, ok := calls[prog.SyscallMap["syz_emit_ethernet"]]; ok {
config.Flags |= ipc.FlagEnableTun
}
if _, ok := calls[sys.SyscallMap["syz_extract_tcp_res"]]; ok {
if _, ok := calls[prog.SyscallMap["syz_extract_tcp_res"]]; ok {
config.Flags |= ipc.FlagEnableTun
}
if faultInjectionEnabled {
@ -407,18 +407,18 @@ func main() {
}
}
func buildCallList(enabledCalls string) map[*sys.Syscall]bool {
calls := make(map[*sys.Syscall]bool)
func buildCallList(enabledCalls string) map[*prog.Syscall]bool {
calls := make(map[*prog.Syscall]bool)
if enabledCalls != "" {
for _, id := range strings.Split(enabledCalls, ",") {
n, err := strconv.ParseUint(id, 10, 64)
if err != nil || n >= uint64(len(sys.Syscalls)) {
if err != nil || n >= uint64(len(prog.Syscalls)) {
panic(fmt.Sprintf("invalid syscall in -calls flag: '%v", id))
}
calls[sys.Syscalls[n]] = true
calls[prog.Syscalls[n]] = true
}
} else {
for _, c := range sys.Syscalls {
for _, c := range prog.Syscalls {
calls[c] = true
}
}
@ -434,7 +434,7 @@ func buildCallList(enabledCalls string) map[*sys.Syscall]bool {
}
}
trans := sys.TransitivelyEnabledCalls(calls)
trans := prog.TransitivelyEnabledCalls(calls)
for c := range calls {
if !trans[c] {
Logf(1, "disabling transitively unsupported syscall: %v", c.Name)

View File

@ -24,7 +24,6 @@ import (
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/pkg/report"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys"
)
const dateFormat = "Jan 02 2006 15:04:05 MST"
@ -196,7 +195,7 @@ func (mgr *Manager) httpPrio(w http.ResponseWriter, r *http.Request) {
mgr.minimizeCorpus()
call := r.FormValue("call")
idx := -1
for i, c := range sys.Syscalls {
for i, c := range prog.Syscalls {
if c.CallName == call {
idx = i
break
@ -209,7 +208,7 @@ func (mgr *Manager) httpPrio(w http.ResponseWriter, r *http.Request) {
data := &UIPrioData{Call: call}
for i, p := range mgr.prios[idx] {
data.Prios = append(data.Prios, UIPrio{sys.Syscalls[i].Name, p})
data.Prios = append(data.Prios, UIPrio{prog.Syscalls[i].Name, p})
}
sort.Sort(UIPrioArray(data.Prios))

View File

@ -29,6 +29,7 @@ import (
"github.com/google/syzkaller/pkg/repro"
. "github.com/google/syzkaller/pkg/rpctype"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
"github.com/google/syzkaller/syz-manager/mgrconfig"
"github.com/google/syzkaller/vm"
)

View File

@ -12,7 +12,8 @@ import (
"github.com/google/syzkaller/pkg/config"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
"github.com/google/syzkaller/vm"
)
@ -149,7 +150,7 @@ func load(data []byte, filename string) (*Config, map[int]bool, error) {
}
func parseSyscalls(cfg *Config) (map[int]bool, error) {
match := func(call *sys.Syscall, str string) bool {
match := func(call *prog.Syscall, str string) bool {
if str == call.CallName || str == call.Name {
return true
}
@ -163,7 +164,7 @@ func parseSyscalls(cfg *Config) (map[int]bool, error) {
if len(cfg.Enable_Syscalls) != 0 {
for _, c := range cfg.Enable_Syscalls {
n := 0
for _, call := range sys.Syscalls {
for _, call := range prog.Syscalls {
if match(call, c) {
syscalls[call.ID] = true
n++
@ -174,13 +175,13 @@ func parseSyscalls(cfg *Config) (map[int]bool, error) {
}
}
} else {
for _, call := range sys.Syscalls {
for _, call := range prog.Syscalls {
syscalls[call.ID] = true
}
}
for _, c := range cfg.Disable_Syscalls {
n := 0
for _, call := range sys.Syscalls {
for _, call := range prog.Syscalls {
if match(call, c) {
delete(syscalls, call.ID)
n++
@ -191,7 +192,7 @@ func parseSyscalls(cfg *Config) (map[int]bool, error) {
}
}
// mmap is used to allocate memory.
syscalls[sys.SyscallMap["mmap"].ID] = true
syscalls[prog.SyscallMap["mmap"].ID] = true
return syscalls, nil
}

View File

@ -23,6 +23,7 @@ import (
. "github.com/google/syzkaller/pkg/log"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
var (

View File

@ -13,6 +13,7 @@ import (
"time"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
var (

View File

@ -18,7 +18,7 @@ import (
"github.com/google/syzkaller/pkg/ipc"
. "github.com/google/syzkaller/pkg/log"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys"
_ "github.com/google/syzkaller/sys"
)
var (
@ -129,21 +129,21 @@ func readCorpus() []*prog.Prog {
return progs
}
func buildCallList() map[*sys.Syscall]bool {
func buildCallList() map[*prog.Syscall]bool {
calls, err := host.DetectSupportedSyscalls()
if err != nil {
Logf(0, "failed to detect host supported syscalls: %v", err)
calls = make(map[*sys.Syscall]bool)
for _, c := range sys.Syscalls {
calls = make(map[*prog.Syscall]bool)
for _, c := range prog.Syscalls {
calls[c] = true
}
}
for _, c := range sys.Syscalls {
for _, c := range prog.Syscalls {
if !calls[c] {
Logf(0, "disabling unsupported syscall: %v", c.Name)
}
}
trans := sys.TransitivelyEnabledCalls(calls)
trans := prog.TransitivelyEnabledCalls(calls)
for c := range calls {
if !trans[c] {
Logf(0, "disabling transitively unsupported syscall: %v", c.Name)

View File

@ -18,6 +18,7 @@ import (
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
)
func main() {