From 2376f0f937b8e6b457ef1fdf088b8b7059dcb0e2 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 14 May 2019 16:21:19 +0200 Subject: pkg/compiler: allow to refer to syscall arguments in len paths This allows to use len[syscall:arg] expressions. --- docs/syscall_descriptions_syntax.md | 14 ++++++++++---- executor/defs.h | 2 +- pkg/compiler/check.go | 34 +++++++++++++++++++++------------- pkg/compiler/testdata/all.txt | 3 ++- pkg/compiler/testdata/errors2.txt | 2 ++ prog/size.go | 17 ++++++++++------- prog/size_test.go | 4 ++-- sys/test/gen/64.go | 6 ++++-- sys/test/test.txt | 1 + 9 files changed, 53 insertions(+), 30 deletions(-) diff --git a/docs/syscall_descriptions_syntax.md b/docs/syscall_descriptions_syntax.md index e3318d300..25b0e0e65 100644 --- a/docs/syscall_descriptions_syntax.md +++ b/docs/syscall_descriptions_syntax.md @@ -252,7 +252,9 @@ s2 { `len` argument can also be a path expression which allows more complex addressing. Path expressions are similar to C field references, but also allow -referencing parent and sibling elements. For example: +referencing parent and sibling elements. A special reference `syscall` used +in the beginning of the path allows to refer directly to the syscall arguments. +For example: ``` s1 { @@ -271,13 +273,17 @@ s3 { # This refers to the array d in the sibling s2. f len[s1:a:d, int32] # This refers to the array k in the child s4. - g len[h:i, int32] - h ptr[in, s4] + g len[i:j, int32] +# This refers to syscall argument l. + h len[syscall:l, int32] + i ptr[in, s4] } s4 { - i array[int8] + j array[int8] } + +foo(k ptr[in, s1], l ptr[in, array[int8]]) ``` ## Proc diff --git a/executor/defs.h b/executor/defs.h index cd8cfae38..eae412e55 100644 --- a/executor/defs.h +++ b/executor/defs.h @@ -165,7 +165,7 @@ #if GOARCH_64 #define GOARCH "64" -#define SYZ_REVISION "3218225be4c9aad40c39be2b8bcb3008fd76ff1e" +#define SYZ_REVISION "596ee9bf31191a84ff800056cadc632de17b3b28" #define SYZ_EXECUTOR_USES_FORK_SERVER 0 #define SYZ_EXECUTOR_USES_SHMEM 0 #define SYZ_PAGE_SIZE 4096 diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 8442f70ec..0b296e2ea 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -179,7 +179,7 @@ func (comp *compiler) checkFieldGroup(fields []*ast.Field, what, ctx string) { existing := make(map[string]bool) for _, f := range fields { fn := f.Name.Name - if fn == prog.ParentRef { + if fn == prog.ParentRef || fn == prog.SyscallRef { comp.error(f.Pos, "reserved %v name %v in %v", what, fn, ctx) } if existing[fn] { @@ -347,10 +347,18 @@ func (comp *compiler) checkLenType(t0, t *ast.Type, parents []parentDesc, func (comp *compiler) checkLenTarget(arg, t0, t *ast.Type, parents []parentDesc, warned map[string]bool) { targets := append([]*ast.Type{arg}, arg.Colon...) - if len(targets) != 1 { - for _, target := range targets { - if target.Ident == prog.ParentRef { - comp.error(target.Pos, "%v can't be part of path expressions", prog.ParentRef) + for i, target := range targets { + if target.Ident == prog.ParentRef && len(targets) != 1 { + comp.error(target.Pos, "%v can't be part of path expressions", prog.ParentRef) + return + } + if target.Ident == prog.SyscallRef { + if i != 0 { + comp.error(target.Pos, "syscall can't be in the middle of path expressions") + return + } + if len(targets) == 1 { + comp.error(targets[0].Pos, "no argument name after syscall reference") return } } @@ -405,15 +413,15 @@ func (comp *compiler) checkLenTargetRec(t0, t *ast.Type, targets []*ast.Type, } for pi := len(parents) - 1; pi >= 0; pi-- { parent := parents[pi] - if parent.name == "" || parent.name != target.Ident && target.Ident != prog.ParentRef { - continue - } - if len(targets) != 0 { - parents1 := make([]parentDesc, pi+1) - copy(parents1, parents[:pi+1]) - comp.checkLenTargetRec(t0, t, targets, parents1, warned) + if parent.name != "" && (parent.name == target.Ident || target.Ident == prog.ParentRef) || + parent.name == "" && target.Ident == prog.SyscallRef { + if len(targets) != 0 { + parents1 := make([]parentDesc, pi+1) + copy(parents1, parents[:pi+1]) + comp.checkLenTargetRec(t0, t, targets, parents1, warned) + } + return } - return } comp.error(target.Pos, "%v target %v does not exist", t.Ident, target.Ident) } diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index 7acb47743..25461ff9a 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -72,6 +72,7 @@ foo$len_var1(a ptr[in, array[string]], b ptr[in, len[a, int32]]) len_expr1 { f11 len_expr2 + f12 bytesize[syscall:b, int32] } len_expr2 { @@ -95,7 +96,7 @@ len_expr4 { f41 int32 } -foo$len_expr(a ptr[in, len_expr1]) +foo$len_expr(a ptr[in, len_expr1], b ptr[in, array[int8, 3]]) # Pointer type. diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt index 6b7737ef5..311be3ea9 100644 --- a/pkg/compiler/testdata/errors2.txt +++ b/pkg/compiler/testdata/errors2.txt @@ -145,6 +145,8 @@ slen1 { f3 len[f0:parent, int32] ### parent can't be part of path expressions f4 len[slen2:f, int32] ### len path slen2 does not refer to a struct f5 len[slen22:f, int32] ### len path slen22 does not refer to a struct + f6 len[syscall, int32] ### no argument name after syscall reference + f7 len[syscall:b, int32] ### len target b does not exist slen2 ptr[in, array[slen2]] slen21 slen2 slen22 array[slen2] diff --git a/prog/size.go b/prog/size.go index ab8e69292..5586d0da5 100644 --- a/prog/size.go +++ b/prog/size.go @@ -11,9 +11,11 @@ import ( const ( // Special reference to the outer struct used in len targets. ParentRef = "parent" + // Special reference directly to syscall arguments used in len targets. + SyscallRef = "syscall" ) -func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg, autos map[Arg]bool) { +func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg, syscallArgs []Arg, autos map[Arg]bool) { for _, arg := range args { if arg = InnerArg(arg); arg == nil { continue // Pointer to optional len field, no need to fill in value. @@ -29,7 +31,11 @@ func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg, autos map[ delete(autos, arg) } a := arg.(*ConstArg) - target.assignSize(a, a, typ.Path, args, parentsMap) + if typ.Path[0] == SyscallRef { + target.assignSize(a, nil, typ.Path[1:], syscallArgs, parentsMap) + } else { + target.assignSize(a, a, typ.Path, args, parentsMap) + } } } @@ -53,9 +59,6 @@ func (target *Target) assignSize(dst *ConstArg, pos Arg, path []string, args []A if len(path) == 0 { dst.Val = target.computeSize(buf, dst.Type().(*LenType)) } else { - if path[0] == ParentRef { - buf = parentsMap[buf] - } target.assignSize(dst, buf, path, buf.(*GroupArg).Inner, parentsMap) } return @@ -119,11 +122,11 @@ func (target *Target) assignSizesArray(args []Arg, autos map[Arg]bool) { } }) } - target.assignSizes(args, parentsMap, autos) + target.assignSizes(args, parentsMap, args, autos) for _, arg := range args { ForeachSubArg(arg, func(arg Arg, _ *ArgCtx) { if _, ok := arg.Type().(*StructType); ok { - target.assignSizes(arg.(*GroupArg).Inner, parentsMap, autos) + target.assignSizes(arg.(*GroupArg).Inner, parentsMap, args, autos) } }) } diff --git a/prog/size_test.go b/prog/size_test.go index 1962b3fc6..613104bf1 100644 --- a/prog/size_test.go +++ b/prog/size_test.go @@ -152,8 +152,8 @@ func TestAssignSize(t *testing.T) { "test$length29(&(0x7f0000000000)={'./a\\x00', './b/c\\x00', 0xa, 0x14, 0x21})", }, { - "test$length30(&(0x7f0000000000)={{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {'a', 'aaa', 'aaaaa', 'aaaaaa'}, &(0x7f0000000000)={'a', 'aaa', 'aaaaa', 'aaaaaa'}, &(0x7f0000000000)=&(0x7f0000000000)={'a', 'aaa', 'aaaaa', 'aaaaaa'}, 0x0}}, 0x0, &(0x7f0000000000)=0x0, 0x0)", - "test$length30(&(0x7f0000000000)={{{0x0, 0x18, 0x1, 0x3, 0x5, 0x6}, {'a', 'aaa', 'aaaaa', 'aaaaaa'}, &(0x7f0000000000)={'a', 'aaa', 'aaaaa', 'aaaaaa'}, &(0x7f0000000000)=&(0x7f0000000000)={'a', 'aaa', 'aaaaa', 'aaaaaa'}, 0x2}}, 0x40, &(0x7f0000000000)=0x18, 0x2)", + "test$length30(&(0x7f0000000000)={{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {'a', 'aaa', 'aaaaa', 'aaaaaa'}, &(0x7f0000000000)={'a', 'aaa', 'aaaaa', 'aaaaaa'}, &(0x7f0000000000)=&(0x7f0000000000)={'a', 'aaa', 'aaaaa', 'aaaaaa'}, 0x0}, 0x0}, 0x0, &(0x7f0000000000)=0x0, 0x0)", + "test$length30(&(0x7f0000000000)={{{0x0, 0x18, 0x1, 0x3, 0x5, 0x6}, {'a', 'aaa', 'aaaaa', 'aaaaaa'}, &(0x7f0000000000)={'a', 'aaa', 'aaaaa', 'aaaaaa'}, &(0x7f0000000000)=&(0x7f0000000000)={'a', 'aaa', 'aaaaa', 'aaaaaa'}, 0x2}, 0x4}, 0x40, &(0x7f0000000000)=0x18, 0x2)", }, } for i, test := range tests { diff --git a/sys/test/gen/64.go b/sys/test/gen/64.go index c07a033db..09797261d 100644 --- a/sys/test/gen/64.go +++ b/sys/test/gen/64.go @@ -90,8 +90,10 @@ var structDescs_64 = []*KeyedStruct{ {Key: StructKey{Name: "explicitly_sized_union"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "explicitly_sized_union", TypeSize: 42}, Fields: []Type{ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}}, }}}, - {Key: StructKey{Name: "len_expr1"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_expr1", TypeSize: 64}, Fields: []Type{ + {Key: StructKey{Name: "len_expr1"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_expr1", TypeSize: 72}, Fields: []Type{ &StructType{Key: StructKey{Name: "len_expr2"}, FldName: "f11"}, + &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "bytesize", FldName: "f12", TypeSize: 4}}, BitSize: 8, Path: []string{"syscall", "a2"}}, + &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 4}}, IsPad: true}, }}}, {Key: StructKey{Name: "len_expr2"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_expr2", TypeSize: 64}, Fields: []Type{ &StructType{Key: StructKey{Name: "len_expr3"}, FldName: "f21"}, @@ -1003,4 +1005,4 @@ var consts_64 = []ConstValue{ {Name: "SYS_unsupported"}, } -const revision_64 = "3218225be4c9aad40c39be2b8bcb3008fd76ff1e" +const revision_64 = "596ee9bf31191a84ff800056cadc632de17b3b28" diff --git a/sys/test/test.txt b/sys/test/test.txt index 9fd037bf3..73c43d83d 100644 --- a/sys/test/test.txt +++ b/sys/test/test.txt @@ -432,6 +432,7 @@ test$length29(a ptr[in, static_filename]) len_expr1 { f11 len_expr2 + f12 bytesize[syscall:a2, int32] } len_expr2 { -- cgit mrf-deployment