diff options
47 files changed, 793 insertions, 654 deletions
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 7b0cf34aa..99ac1d447 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -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) } diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 8cccf53c4..f6641f9c9 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -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 diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index e3b7ffd66..eeeed011c 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -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, diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index 2a398e3fb..193617574 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -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)) } diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index b46fda351..e1b32e752 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -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 diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go index e4e9e1f7f..fbe984b3c 100644 --- a/pkg/csource/csource_test.go +++ b/pkg/csource/csource_test.go @@ -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) { diff --git a/pkg/host/host.go b/pkg/host/host.go index 9aafbce6e..0fa66dfa4 100644 --- a/pkg/host/host.go +++ b/pkg/host/host.go @@ -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] diff --git a/pkg/host/host_test.go b/pkg/host/host_test.go index 1eea00fe6..dc9225d5a 100644 --- a/pkg/host/host_test.go +++ b/pkg/host/host_test.go @@ -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) } diff --git a/pkg/ipc/ipc_test.go b/pkg/ipc/ipc_test.go index 68fbb94cd..b6bfca81d 100644 --- a/pkg/ipc/ipc_test.go +++ b/pkg/ipc/ipc_test.go @@ -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 diff --git a/prog/analysis.go b/prog/analysis.go index 05837131a..009a15a21 100644 --- a/prog/analysis.go +++ b/prog/analysis.go @@ -10,8 +10,6 @@ package prog import ( "fmt" - - . "github.com/google/syzkaller/sys" ) const ( @@ -68,46 +66,18 @@ 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 - } - 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) - } - } + for i := uint64(0); i < npages; i++ { + s.pages[start+i] = mapped } } } -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 - } -} - func foreachSubargImpl(arg Arg, parent *[]Arg, f func(arg, base Arg, parent *[]Arg)) { var rec func(arg, base Arg, parent *[]Arg) rec = func(arg, base Arg, parent *[]Arg) { @@ -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 { diff --git a/prog/checksum.go b/prog/checksum.go index 0c8f7210d..b5226e715 100644 --- a/prog/checksum.go +++ b/prog/checksum.go @@ -5,8 +5,6 @@ package prog import ( "fmt" - - . "github.com/google/syzkaller/sys" ) type CsumChunkKind int diff --git a/prog/checksum_test.go b/prog/checksum_test.go index 205450255..004769328 100644 --- a/prog/checksum_test.go +++ b/prog/checksum_test.go @@ -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) } } } diff --git a/sys/decl_test.go b/prog/decl_test.go index a156f4f61..e716cdf5e 100644 --- a/sys/decl_test.go +++ b/prog/decl_test.go @@ -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) } } diff --git a/prog/encoding.go b/prog/encoding.go index 2081b1abb..a6ded73ca 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -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 { diff --git a/prog/encoding_test.go b/prog/encoding_test.go index f4036b458..c58fe7dc8 100644 --- a/prog/encoding_test.go +++ b/prog/encoding_test.go @@ -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{}) diff --git a/prog/encodingexec.go b/prog/encodingexec.go index d50e4f3be..a4f41a694 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -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 diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go index 37bfe04c0..9a2dd1d1e 100644 --- a/prog/encodingexec_test.go +++ b/prog/encodingexec_test.go @@ -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 { diff --git a/prog/export_test.go b/prog/export_test.go new file mode 100644 index 000000000..c5337d695 --- /dev/null +++ b/prog/export_test.go @@ -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 +} diff --git a/prog/hints.go b/prog/hints.go index ba8131081..e268d46a6 100644 --- a/prog/hints.go +++ b/prog/hints.go @@ -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)) } } diff --git a/prog/hints_test.go b/prog/hints_test.go index 5409925bf..3f0a10726 100644 --- a/prog/hints_test.go +++ b/prog/hints_test.go @@ -7,8 +7,6 @@ import ( "fmt" "reflect" "testing" - - . "github.com/google/syzkaller/sys" ) type ConstArgTest struct { diff --git a/prog/mutation.go b/prog/mutation.go index a45a02fe1..e793e28e4 100644 --- a/prog/mutation.go +++ b/prog/mutation.go @@ -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 } diff --git a/prog/mutation_test.go b/prog/mutation_test.go index 2f70e0a5d..060fe5f33 100644 --- a/prog/mutation_test.go +++ b/prog/mutation_test.go @@ -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) } diff --git a/prog/prio.go b/prog/prio.go index 92d2ea3db..c64ae319b 100644 --- a/prog/prio.go +++ b/prog/prio.go @@ -7,8 +7,6 @@ import ( "fmt" "math/rand" "sort" - - . "github.com/google/syzkaller/sys" ) // Calulation of call-to-call priorities. diff --git a/prog/prog.go b/prog/prog.go index 6e18f3a4a..579bac4e0 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -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) } } diff --git a/prog/prog_test.go b/prog/prog_test.go index b377846fb..69aa9c166 100644 --- a/prog/prog_test.go +++ b/prog/prog_test.go @@ -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) diff --git a/prog/rand.go b/prog/rand.go index 110436e37..1993d7461 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -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") } diff --git a/prog/size.go b/prog/size.go index b715f6f26..b9920c19b 100644 --- a/prog/size.go +++ b/prog/size.go @@ -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()) } } } diff --git a/prog/size_test.go b/prog/size_test.go index c72e5283f..778725d49 100644 --- a/prog/size_test.go +++ b/prog/size_test.go @@ -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 { diff --git a/prog/target.go b/prog/target.go new file mode 100644 index 000000000..f5dde79f4 --- /dev/null +++ b/prog/target.go @@ -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) +) diff --git a/sys/decl.go b/prog/types.go index 82d27e915..6fdc0d975 100644 --- a/sys/decl.go +++ b/prog/types.go @@ -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 - } -} diff --git a/prog/validation.go b/prog/validation.go index 51520b29b..d5b4a4c04 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -5,8 +5,6 @@ package prog import ( "fmt" - - . "github.com/google/syzkaller/sys" ) var debug = false // enabled in tests diff --git a/sys/init.go b/sys/init.go new file mode 100644 index 000000000..edefe3a52 --- /dev/null +++ b/sys/init.go @@ -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 + } + } +} diff --git a/sys/sys_386.go b/sys/sys_386.go index f0eebd212..a699a8893 100644 --- a/sys/sys_386.go +++ b/sys/sys_386.go @@ -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}}}, diff --git a/sys/sys_amd64.go b/sys/sys_amd64.go index 0b85dda44..5325d7f13 100644 --- a/sys/sys_amd64.go +++ b/sys/sys_amd64.go @@ -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}}}, diff --git a/sys/sys_arm.go b/sys/sys_arm.go index adcd5dbef..128fd836d 100644 --- a/sys/sys_arm.go +++ b/sys/sys_arm.go @@ -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}}}, diff --git a/sys/sys_arm64.go b/sys/sys_arm64.go index 435eb92b6..bfc975594 100644 --- a/sys/sys_arm64.go +++ b/sys/sys_arm64.go @@ -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}}}, diff --git a/sys/sys_ppc64le.go b/sys/sys_ppc64le.go index 52a8bca35..332c3e6b2 100644 --- a/sys/sys_ppc64le.go +++ b/sys/sys_ppc64le.go @@ -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}}}, diff --git a/sys/syz-sysgen/syscallnr.go b/sys/syz-sysgen/syscallnr.go index 02c676cf0..da427a553 100644 --- a/sys/syz-sysgen/syscallnr.go +++ b/sys/syz-sysgen/syscallnr.go @@ -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, } diff --git a/sys/syz-sysgen/sysgen.go b/sys/syz-sysgen/sysgen.go index 7381f1edb..f09835aef 100644 --- a/sys/syz-sysgen/sysgen.go +++ b/sys/syz-sysgen/sysgen.go @@ -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") diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go index 8f8a62829..8c9e5fbdf 100644 --- a/syz-fuzzer/fuzzer.go +++ b/syz-fuzzer/fuzzer.go @@ -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) diff --git a/syz-manager/html.go b/syz-manager/html.go index 566809457..a9a9b641a 100644 --- a/syz-manager/html.go +++ b/syz-manager/html.go @@ -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)) diff --git a/syz-manager/manager.go b/syz-manager/manager.go index 653e0b428..16bd7edbd 100644 --- a/syz-manager/manager.go +++ b/syz-manager/manager.go @@ -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" ) diff --git a/syz-manager/mgrconfig/mgrconfig.go b/syz-manager/mgrconfig/mgrconfig.go index 4eacbfd7f..8423ddd46 100644 --- a/syz-manager/mgrconfig/mgrconfig.go +++ b/syz-manager/mgrconfig/mgrconfig.go @@ -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 } diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go index de2e1f7f3..1bedc09ea 100644 --- a/tools/syz-execprog/execprog.go +++ b/tools/syz-execprog/execprog.go @@ -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 ( diff --git a/tools/syz-mutate/mutate.go b/tools/syz-mutate/mutate.go index 9824db0b1..adda12df7 100644 --- a/tools/syz-mutate/mutate.go +++ b/tools/syz-mutate/mutate.go @@ -13,6 +13,7 @@ import ( "time" "github.com/google/syzkaller/prog" + _ "github.com/google/syzkaller/sys" ) var ( diff --git a/tools/syz-stress/stress.go b/tools/syz-stress/stress.go index d3ad6e9ed..159e7ddde 100644 --- a/tools/syz-stress/stress.go +++ b/tools/syz-stress/stress.go @@ -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) diff --git a/tools/syz-upgrade/upgrade.go b/tools/syz-upgrade/upgrade.go index 0d7c42112..0a28a27fb 100644 --- a/tools/syz-upgrade/upgrade.go +++ b/tools/syz-upgrade/upgrade.go @@ -18,6 +18,7 @@ import ( "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/prog" + _ "github.com/google/syzkaller/sys" ) func main() { |
