From 90d17ab8980674c6a59f47a062adccb37f99b88a Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 16 Apr 2020 17:38:36 +0200 Subject: prog: introduce call attributes Add common infrastructure for syscall attributes. Add few attributes we want, but they are not implemented for now (don't affect behavior, this will follow). --- pkg/compiler/attrs.go | 22 ++++++++++++++ pkg/compiler/check.go | 1 + pkg/compiler/consts.go | 64 +++++++++++++++++++++------------------- pkg/compiler/gen.go | 12 ++++++++ pkg/compiler/testdata/all.txt | 3 ++ pkg/compiler/testdata/errors.txt | 3 ++ 6 files changed, 75 insertions(+), 30 deletions(-) (limited to 'pkg/compiler') diff --git a/pkg/compiler/attrs.go b/pkg/compiler/attrs.go index 245da125f..c0fa04211 100644 --- a/pkg/compiler/attrs.go +++ b/pkg/compiler/attrs.go @@ -4,7 +4,10 @@ package compiler import ( + "reflect" + "github.com/google/syzkaller/pkg/ast" + "github.com/google/syzkaller/prog" ) type attrDesc struct { @@ -23,9 +26,12 @@ var ( structAttrs = makeAttrs(attrPacked, attrSize, attrAlign) unionAttrs = makeAttrs(attrVarlen, attrSize) + callAttrs = make(map[string]*attrDesc) ) func init() { + initCallAttrs() + attrSize.CheckConsts = func(comp *compiler, parent ast.Node, attr *ast.Type) { _, typ, name := parent.Info() if comp.structIsVarlen(name) { @@ -46,6 +52,22 @@ func init() { } } +func initCallAttrs() { + attrs := reflect.TypeOf(prog.SyscallAttrs{}) + for i := 0; i < attrs.NumField(); i++ { + attr := attrs.Field(i) + desc := &attrDesc{Name: attr.Name} + switch attr.Type.Kind() { + case reflect.Bool: + case reflect.Uint64: + desc.HasArg = true + default: + panic("unsupported syscall attribute type") + } + callAttrs[prog.CppName(desc.Name)] = desc + } +} + func structOrUnionAttrs(n *ast.Struct) map[string]*attrDesc { if n.IsUnion { return unionAttrs diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 7ddb662d9..e22f217fd 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -713,6 +713,7 @@ func (comp *compiler) checkCall(n *ast.Call) { if n.Ret != nil { comp.checkType(checkCtx{}, n.Ret, checkIsArg|checkIsRet) } + comp.parseAttrs(callAttrs, n, n.Attrs) } type checkFlags int diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go index 5c0a4e8b2..5a6dbd974 100644 --- a/pkg/compiler/consts.go +++ b/pkg/compiler/consts.go @@ -77,32 +77,11 @@ func (comp *compiler) extractConsts() map[string]*ConstInfo { if comp.target.SyscallNumbers && !strings.HasPrefix(n.CallName, "syz_") { comp.addConst(infos, pos, comp.target.SyscallPrefix+n.CallName) } - } - } - - for _, decl := range comp.desc.Nodes { - switch decl.(type) { - case *ast.Call, *ast.Struct, *ast.Resource, *ast.TypeDef: - comp.foreachType(decl, func(t *ast.Type, desc *typeDesc, - args []*ast.Type, _ prog.IntTypeCommon) { - for i, arg := range args { - if desc.Args[i].Type.Kind == kindInt { - if arg.Ident != "" { - comp.addConst(infos, arg.Pos, arg.Ident) - } - for _, col := range arg.Colon { - if col.Ident != "" { - comp.addConst(infos, col.Pos, col.Ident) - } - } - } + for _, attr := range n.Attrs { + if callAttrs[attr.Ident].HasArg { + comp.addConst(infos, attr.Pos, attr.Args[0].Ident) } - }) - } - } - - for _, decl := range comp.desc.Nodes { - switch n := decl.(type) { + } case *ast.Struct: for _, attr := range n.Attrs { if structOrUnionAttrs(n)[attr.Ident].HasArg { @@ -110,17 +89,36 @@ func (comp *compiler) extractConsts() map[string]*ConstInfo { } } } + switch decl.(type) { + case *ast.Call, *ast.Struct, *ast.Resource, *ast.TypeDef: + comp.extractTypeConsts(infos, decl) + } } - comp.desc.Walk(ast.Recursive(func(n0 ast.Node) { if n, ok := n0.(*ast.Int); ok { comp.addConst(infos, n.Pos, n.Ident) } })) - return convertConstInfo(infos) } +func (comp *compiler) extractTypeConsts(infos map[string]*constInfo, n ast.Node) { + comp.foreachType(n, func(t *ast.Type, desc *typeDesc, args []*ast.Type, _ prog.IntTypeCommon) { + for i, arg := range args { + if desc.Args[i].Type.Kind == kindInt { + if arg.Ident != "" { + comp.addConst(infos, arg.Pos, arg.Ident) + } + for _, col := range arg.Colon { + if col.Ident != "" { + comp.addConst(infos, col.Pos, col.Ident) + } + } + } + } + }) +} + func (comp *compiler) addConst(infos map[string]*constInfo, pos ast.Pos, name string) { if _, builtin := comp.builtinConsts[name]; builtin { return @@ -220,12 +218,18 @@ func (comp *compiler) patchConsts(consts0 map[string]uint64) { } } }) - if n, ok := decl.(*ast.Resource); ok { + switch n := decl.(type) { + case *ast.Resource: for _, v := range n.Values { comp.patchIntConst(v, consts, &missing) } - } - if n, ok := decl.(*ast.Struct); ok { + case *ast.Call: + for _, attr := range n.Attrs { + if callAttrs[attr.Ident].HasArg { + comp.patchTypeConst(attr.Args[0], consts, &missing) + } + } + case *ast.Struct: for _, attr := range n.Attrs { if structOrUnionAttrs(n)[attr.Ident].HasArg { comp.patchTypeConst(attr.Args[0], consts, &missing) diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index baafee0e2..f357adc24 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -5,6 +5,7 @@ package compiler import ( "fmt" + "reflect" "sort" "github.com/google/syzkaller/pkg/ast" @@ -111,6 +112,16 @@ func (comp *compiler) genSyscall(n *ast.Call, argSizes []uint64) *prog.Syscall { if n.Ret != nil { ret = comp.genType(n.Ret, "ret", prog.DirOut, comp.ptrSize) } + var attrs prog.SyscallAttrs + descAttrs := comp.parseAttrs(callAttrs, n, n.Attrs) + for desc, val := range descAttrs { + fld := reflect.ValueOf(&attrs).Elem().FieldByName(desc.Name) + if desc.HasArg { + fld.SetUint(val) + } else { + fld.SetBool(val != 0) + } + } return &prog.Syscall{ Name: n.Name.Name, CallName: n.CallName, @@ -118,6 +129,7 @@ func (comp *compiler) genSyscall(n *ast.Call, argSizes []uint64) *prog.Syscall { MissingArgs: len(argSizes) - len(n.Args), Args: comp.genFieldArray(n.Args, prog.DirIn, argSizes), Ret: ret, + Attrs: attrs, } } diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index 455ccbe60..f5f3f1070 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -14,6 +14,9 @@ foo_9(a ptr[out, ptr[in, string]]) foo_10(a ptr[out, buffer[in]]) foo_11(a int64[1:100, 2]) foo_12(a int64[0:-1, 0x1000]) +foo_13() (disabled) +foo_14() r0 (timeout[100]) +foo_15() r0 (disabled, timeout[C1], prog_timeout[C2]) resource r0[intptr] diff --git a/pkg/compiler/testdata/errors.txt b/pkg/compiler/testdata/errors.txt index 3b77ed4b9..5c7f923d6 100644 --- a/pkg/compiler/testdata/errors.txt +++ b/pkg/compiler/testdata/errors.txt @@ -125,6 +125,9 @@ foo$65(a int32, b len[1]) ### unexpected int 1 for len target argument of len ty foo$66(a int32, b len[a:1]) ### unexpected int 1 after colon, expect identifier foo$67(x int32[1:2:3, opt]) ### unexpected ':' foo$68(a int32[15, 2]) ### first argument of int32 needs to be a range +foo$69() (foo) ### unknown syscall foo$69 attribute foo +foo$70() ("foo") ### unexpected string "foo", expect attribute +foo$71() (42) ### unexpected int 42, expect attribute opt { ### struct uses reserved name opt f1 int32 -- cgit mrf-deployment