aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/syscall_descriptions_syntax.md2
-rw-r--r--executor/defs.h2
-rw-r--r--executor/syscalls.h1
-rw-r--r--pkg/compiler/check.go7
-rw-r--r--pkg/compiler/testdata/all.txt2
-rw-r--r--pkg/compiler/testdata/errors2.txt2
-rw-r--r--pkg/compiler/types.go7
-rw-r--r--prog/size.go22
-rw-r--r--prog/size_test.go4
-rw-r--r--prog/types.go1
-rw-r--r--sys/test/gen/64.go26
-rw-r--r--sys/test/test.txt21
12 files changed, 86 insertions, 11 deletions
diff --git a/docs/syscall_descriptions_syntax.md b/docs/syscall_descriptions_syntax.md
index 25b0e0e65..cb5249ab1 100644
--- a/docs/syscall_descriptions_syntax.md
+++ b/docs/syscall_descriptions_syntax.md
@@ -50,6 +50,8 @@ rest of the type-options are type-specific:
argname of the object
"bitsize": similar to "len", but always denotes the size in bits, type-options:
argname of the object
+"offsetof": offset of the field from the beginning of the parent struct, type-options:
+ field
"vma"/"vma64": a pointer to a set of pages (used as input for mmap/munmap/mremap/madvise), type-options:
optional number of pages (e.g. vma[7]), or a range of pages (e.g. vma[2-4])
vma64 has size of 8 bytes regardless of target pointer size
diff --git a/executor/defs.h b/executor/defs.h
index a6ec85997..bf0d34fee 100644
--- a/executor/defs.h
+++ b/executor/defs.h
@@ -165,7 +165,7 @@
#if GOARCH_64
#define GOARCH "64"
-#define SYZ_REVISION "e07c8657b55348a9385e59d435ee7ad303ccc728"
+#define SYZ_REVISION "74c87d08a1f72c38c85e889813b60823a1e5755c"
#define SYZ_EXECUTOR_USES_FORK_SERVER 0
#define SYZ_EXECUTOR_USES_SHMEM 0
#define SYZ_PAGE_SIZE 4096
diff --git a/executor/syscalls.h b/executor/syscalls.h
index 8c6e6f0fb..a0810f527 100644
--- a/executor/syscalls.h
+++ b/executor/syscalls.h
@@ -15509,6 +15509,7 @@ const call_t syscalls[] = {
{"test$length9", 0},
{"test$missing_resource", 0},
{"test$missing_struct", 0},
+ {"test$offsetof0", 0},
{"test$opt0", 0},
{"test$opt1", 0},
{"test$opt2", 0},
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go
index 0b296e2ea..24acfe50f 100644
--- a/pkg/compiler/check.go
+++ b/pkg/compiler/check.go
@@ -415,7 +415,12 @@ func (comp *compiler) checkLenTargetRec(t0, t *ast.Type, targets []*ast.Type,
parent := parents[pi]
if parent.name != "" && (parent.name == target.Ident || target.Ident == prog.ParentRef) ||
parent.name == "" && target.Ident == prog.SyscallRef {
- if len(targets) != 0 {
+ if len(targets) == 0 {
+ if t.Ident == "offsetof" {
+ comp.error(target.Pos, "%v must refer to fields", t.Ident)
+ return
+ }
+ } else {
parents1 := make([]parentDesc, pi+1)
copy(parents1, parents[:pi+1])
comp.checkLenTargetRec(t0, t, targets, parents1, warned)
diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt
index 25461ff9a..68629c685 100644
--- a/pkg/compiler/testdata/all.txt
+++ b/pkg/compiler/testdata/all.txt
@@ -90,6 +90,8 @@ len_expr3 {
f34 bytesize[len_expr1:f11:f22:f41, int32]
f35 bytesize[len_expr2:f23:f41, int32]
f36 bytesize[len_expr2:f24:f41, int32]
+ f37 offsetof[f32, int32]
+ f38 offsetof[len_expr2:f21, int32]
}
len_expr4 {
diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt
index 311be3ea9..db8f87e25 100644
--- a/pkg/compiler/testdata/errors2.txt
+++ b/pkg/compiler/testdata/errors2.txt
@@ -147,6 +147,8 @@ slen1 {
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
+ f8 offsetof[parent, int32] ### offsetof must refer to fields
+ f9 offsetof[slen1, int32] ### offsetof must refer to fields
slen2 ptr[in, array[slen2]]
slen21 slen2
slen22 array[slen2]
diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go
index 6d9211686..18027615d 100644
--- a/pkg/compiler/types.go
+++ b/pkg/compiler/types.go
@@ -204,13 +204,14 @@ var typeArray = &typeDesc{
}
var typeLen = &typeDesc{
- Names: []string{"len", "bytesize", "bytesize2", "bytesize4", "bytesize8", "bitsize"},
+ Names: []string{"len", "bytesize", "bytesize2", "bytesize4", "bytesize8", "bitsize", "offsetof"},
CanBeArgRet: canBeArg,
CantBeOpt: true,
NeedBase: true,
Args: []namedArg{{Name: "len target", Type: typeArgLenTarget}},
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
var bitSize uint64
+ var offset bool
switch t.Ident {
case "bytesize":
bitSize = 8
@@ -219,6 +220,9 @@ var typeLen = &typeDesc{
bitSize = byteSize * 8
case "bitsize":
bitSize = 1
+ case "offsetof":
+ bitSize = 8
+ offset = true
}
path := []string{args[0].Ident}
for _, col := range args[0].Colon {
@@ -228,6 +232,7 @@ var typeLen = &typeDesc{
IntTypeCommon: base,
Path: path,
BitSize: bitSize,
+ Offset: offset,
}
},
}
diff --git a/prog/size.go b/prog/size.go
index 23248c722..a134f0d10 100644
--- a/prog/size.go
+++ b/prog/size.go
@@ -42,8 +42,12 @@ func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg, syscallArg
func (target *Target) assignSize(dst *ConstArg, pos Arg, path []string, args []Arg, parentsMap map[Arg]Arg) {
elem := path[0]
path = path[1:]
+ var offset uint64
for _, buf := range args {
if elem != buf.Type().FieldName() {
+ if !buf.Type().BitfieldMiddle() {
+ offset += buf.Size()
+ }
continue
}
buf = InnerArg(buf)
@@ -52,7 +56,7 @@ func (target *Target) assignSize(dst *ConstArg, pos Arg, path []string, args []A
return
}
if len(path) == 0 {
- dst.Val = target.computeSize(buf, dst.Type().(*LenType))
+ dst.Val = target.computeSize(buf, offset, dst.Type().(*LenType))
} else {
target.assignSize(dst, buf, path, buf.(*GroupArg).Inner, parentsMap)
}
@@ -61,7 +65,7 @@ func (target *Target) assignSize(dst *ConstArg, pos Arg, path []string, args []A
if elem == ParentRef {
buf := parentsMap[pos]
if len(path) == 0 {
- dst.Val = target.computeSize(buf, dst.Type().(*LenType))
+ dst.Val = target.computeSize(buf, noOffset, dst.Type().(*LenType))
} else {
target.assignSize(dst, buf, path, buf.(*GroupArg).Inner, parentsMap)
}
@@ -77,7 +81,7 @@ func (target *Target) assignSize(dst *ConstArg, pos Arg, path []string, args []A
continue
}
if len(path) == 0 {
- dst.Val = target.computeSize(buf, dst.Type().(*LenType))
+ dst.Val = target.computeSize(buf, noOffset, dst.Type().(*LenType))
} else {
target.assignSize(dst, buf, path, buf.(*GroupArg).Inner, parentsMap)
}
@@ -91,10 +95,14 @@ func (target *Target) assignSize(dst *ConstArg, pos Arg, path []string, args []A
dst.Type().FieldName(), elem, pos.Type().Name(), pos.Type().FieldName(), argNames))
}
-func (target *Target) computeSize(arg Arg, lenType *LenType) uint64 {
- if arg == nil {
- // Arg is an optional pointer, set size to 0.
- return 0
+const noOffset = ^uint64(0)
+
+func (target *Target) computeSize(arg Arg, offset uint64, lenType *LenType) uint64 {
+ if lenType.Offset {
+ if offset == noOffset {
+ panic("offset of a non-field")
+ }
+ return offset * 8 / lenType.BitSize
}
bitSize := lenType.BitSize
if bitSize == 0 {
diff --git a/prog/size_test.go b/prog/size_test.go
index 613104bf1..7b248bd4f 100644
--- a/prog/size_test.go
+++ b/prog/size_test.go
@@ -155,6 +155,10 @@ func TestAssignSize(t *testing.T) {
"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)",
},
+ {
+ "test$offsetof0(&(0x7f0000000000)={0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})",
+ "test$offsetof0(&(0x7f0000000000)={0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x6, 0x8, 0x10, 0x18, 0x18, 0x20})",
+ },
}
for i, test := range tests {
p, err := target.Deserialize([]byte(test.unsizedProg), Strict)
diff --git a/prog/types.go b/prog/types.go
index ebfcbc5ac..7f9569483 100644
--- a/prog/types.go
+++ b/prog/types.go
@@ -255,6 +255,7 @@ func (t *FlagsType) isDefaultArg(arg Arg) bool {
type LenType struct {
IntTypeCommon
BitSize uint64 // want size in multiple of bits instead of array size
+ Offset bool // offset from the beginning of the parent struct or base object
Path []string
}
diff --git a/sys/test/gen/64.go b/sys/test/gen/64.go
index 3e20cff6f..00cba243f 100644
--- a/sys/test/gen/64.go
+++ b/sys/test/gen/64.go
@@ -152,6 +152,27 @@ var structDescs_64 = []*KeyedStruct{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f2", TypeSize: 1}}},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 3}}, IsPad: true},
}}},
+ {Key: StructKey{Name: "offsetof0"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "offsetof0", TypeSize: 72}, Fields: []Type{
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "f0", TypeSize: 4}}},
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}},
+ &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 1}}, IsPad: true},
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int16", FldName: "f2", TypeSize: 2}}},
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f3", TypeSize: 1}}},
+ &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 7}}, IsPad: true},
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int64", FldName: "f4", TypeSize: 8}}},
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "f5", TypeSize: 4}, BitfieldLen: 5, BitfieldMdl: true}},
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "f6", TypeSize: 4}, BitfieldOff: 5, BitfieldLen: 10}},
+ &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 4}}, IsPad: true},
+ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int64", FldName: "f7", TypeSize: 8}}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "offsetof", FldName: "o0", TypeSize: 4}}, BitSize: 8, Offset: true, Path: []string{"f0"}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "offsetof", FldName: "o1", TypeSize: 4}}, BitSize: 8, Offset: true, Path: []string{"f1"}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "offsetof", FldName: "o2", TypeSize: 4}}, BitSize: 8, Offset: true, Path: []string{"f2"}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "offsetof", FldName: "o3", TypeSize: 4}}, BitSize: 8, Offset: true, Path: []string{"f3"}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "offsetof", FldName: "o4", TypeSize: 4}}, BitSize: 8, Offset: true, Path: []string{"f4"}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "offsetof", FldName: "o5", TypeSize: 4}}, BitSize: 8, Offset: true, Path: []string{"f5"}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "offsetof", FldName: "o6", TypeSize: 4}}, BitSize: 8, Offset: true, Path: []string{"f6"}},
+ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "offsetof", FldName: "o7", TypeSize: 4}}, BitSize: 8, Offset: true, Path: []string{"f7"}},
+ }}},
{Key: StructKey{Name: "serialize0_struct"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "serialize0_struct", TypeSize: 15}, Fields: []Type{
&BufferType{TypeCommon: TypeCommon{TypeName: "string", FldName: "a", TypeSize: 10}, Kind: 2, SubKind: "serialize_strings", Values: []string{"aaa\x00\x00\x00\x00\x00\x00\x00", "bbb\x00\x00\x00\x00\x00\x00\x00"}},
&BufferType{TypeCommon: TypeCommon{TypeName: "string", FldName: "b", TypeSize: 5}, Kind: 2, SubKind: "serialize_strings", Values: []string{"aaa\x00\x00", "bbb\x00\x00"}},
@@ -896,6 +917,9 @@ var syscalls_64 = []*Syscall{
{Name: "test$missing_struct", CallName: "test", MissingArgs: 5, Args: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a", TypeSize: 8}, Type: &StructType{Key: StructKey{Name: "syz_use_missing"}}},
}},
+ {Name: "test$offsetof0", CallName: "test", MissingArgs: 5, Args: []Type{
+ &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 8}, Type: &StructType{Key: StructKey{Name: "offsetof0"}}},
+ }},
{Name: "test$opt0", CallName: "test", MissingArgs: 5, Args: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "intptr", FldName: "a0", TypeSize: 8, IsOptional: true}}},
}},
@@ -1010,4 +1034,4 @@ var consts_64 = []ConstValue{
{Name: "SYS_unsupported"},
}
-const revision_64 = "e07c8657b55348a9385e59d435ee7ad303ccc728"
+const revision_64 = "74c87d08a1f72c38c85e889813b60823a1e5755c"
diff --git a/sys/test/test.txt b/sys/test/test.txt
index 1ddc67aa8..a087dd47f 100644
--- a/sys/test/test.txt
+++ b/sys/test/test.txt
@@ -461,6 +461,27 @@ len_expr4 {
test$length30(a0 ptr[in, len_expr1], a1 bytesize[a0:f11], a2 ptr[in, bytesize[a0:f11:f21, int32]], a3 bytesize[a0:f11:f21:f31])
+test$offsetof0(a0 ptr[in, offsetof0])
+
+offsetof0 {
+ f0 int32
+ f1 int8
+ f2 int16
+ f3 int8
+ f4 int64
+ f5 int32:5
+ f6 int32:10
+ f7 int64
+ o0 offsetof[f0, int32]
+ o1 offsetof[f1, int32]
+ o2 offsetof[f2, int32]
+ o3 offsetof[f3, int32]
+ o4 offsetof[f4, int32]
+ o5 offsetof[f5, int32]
+ o6 offsetof[f6, int32]
+ o7 offsetof[f7, int32]
+}
+
# Big endian
test$end0(a0 ptr[in, syz_end_int_struct])