aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--prog/analysis.go54
-rw-r--r--prog/rand.go3
-rw-r--r--prog/size_test.go6
-rw-r--r--sys/README.md30
-rw-r--r--sys/test.txt22
5 files changed, 97 insertions, 18 deletions
diff --git a/prog/analysis.go b/prog/analysis.go
index a6ee3885b..81c17c9ee 100644
--- a/prog/analysis.go
+++ b/prog/analysis.go
@@ -174,14 +174,10 @@ func generateSize(arg *Arg, lenType *sys.LenType) *Arg {
}
}
-func assignSizes(args []*Arg) {
+func assignSizes(args []*Arg, parentsMap map[*Arg]*Arg) {
// Create a map of args and calculate size of the whole struct.
argsMap := make(map[string]*Arg)
- var parentSize uintptr
for _, arg := range args {
- if arg.Type.BitfieldLength() == 0 || arg.Type.BitfieldLast() {
- parentSize += arg.Size()
- }
if sys.IsPad(arg.Type) {
continue
}
@@ -194,32 +190,60 @@ func assignSizes(args []*Arg) {
continue // Pointer to optional len field, no need to fill in value.
}
if typ, ok := arg.Type.(*sys.LenType); ok {
+ buf, ok := argsMap[typ.Buf]
+ if ok {
+ *arg = *generateSize(buf.InnerArg(), typ)
+ continue
+ }
+
if typ.Buf == "parent" {
- arg.Val = parentSize
+ arg.Val = parentsMap[arg].Size()
if typ.ByteSize != 0 {
arg.Val /= typ.ByteSize
}
continue
}
- buf, ok := argsMap[typ.Buf]
- if !ok {
- panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v",
- typ.FieldName(), typ.Buf, argsMap))
+ sizeAssigned := false
+ for parent := parentsMap[arg]; parent != nil; parent = parentsMap[parent] {
+ if typ.Buf == parent.Type.Name() {
+ arg.Val = parent.Size()
+ if typ.ByteSize != 0 {
+ arg.Val /= typ.ByteSize
+ }
+ sizeAssigned = true
+ break
+ }
+ }
+ if sizeAssigned {
+ continue
}
- *arg = *generateSize(buf.InnerArg(), typ)
+ panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v",
+ typ.FieldName(), typ.Buf, argsMap))
}
}
}
-func assignSizesCall(c *Call) {
- assignSizes(c.Args)
- foreachArg(c, func(arg, base *Arg, parent *[]*Arg) {
+func assignSizesArray(args []*Arg) {
+ parentsMap := make(map[*Arg]*Arg)
+ foreachArgArray(&args, nil, func(arg, base *Arg, _ *[]*Arg) {
if _, ok := arg.Type.(*sys.StructType); ok {
- assignSizes(arg.Inner)
+ for _, field := range arg.Inner {
+ parentsMap[field.InnerArg()] = arg
+ }
}
})
+ assignSizes(args, parentsMap)
+ foreachArgArray(&args, nil, func(arg, base *Arg, _ *[]*Arg) {
+ if _, ok := arg.Type.(*sys.StructType); ok {
+ assignSizes(arg.Inner, parentsMap)
+ }
+ })
+}
+
+func assignSizesCall(c *Call) {
+ assignSizesArray(c.Args)
}
func sanitizeCall(c *Call) {
diff --git a/prog/rand.go b/prog/rand.go
index 4645db811..4a7bbe08d 100644
--- a/prog/rand.go
+++ b/prog/rand.go
@@ -557,6 +557,7 @@ func (r *randGen) generateParticularCall(s *state, meta *sys.Call) (calls []*Cal
Ret: returnArg(meta.Ret),
}
c.Args, calls = r.generateArgs(s, meta.Args)
+ assignSizesCall(c)
calls = append(calls, c)
for _, c1 := range calls {
sanitizeCall(c1)
@@ -601,8 +602,6 @@ func (r *randGen) generateArgs(s *state, types []sys.Type) ([]*Arg, []*Call) {
calls = append(calls, calls1...)
}
- assignSizes(args)
-
return args, calls
}
diff --git a/prog/size_test.go b/prog/size_test.go
index 0b7e5fb98..f6e4ab17c 100644
--- a/prog/size_test.go
+++ b/prog/size_test.go
@@ -72,7 +72,7 @@ func TestAssignSize(t *testing.T) {
},
{
"syz_test$length8(&(0x7f000001f000)={0x00, {0xff, 0x0, 0x00, [0xff, 0xff, 0xff]}, [{0xff, 0x0, 0x00, [0xff, 0xff, 0xff]}], 0x00, 0x0, [0xff, 0xff]})",
- "syz_test$length8(&(0x7f000001f000)={0x32, {0xff, 0x1, 0x10, [0xff, 0xff, 0xff]}, [{0xff, 0x1, 0x10, [0xff, 0xff, 0xff]}], 0x10, 0x1, [0xff, 0xff]})",
+ "syz_test$length8(&(0x7f000001f000)={0x38, {0xff, 0x1, 0x10, [0xff, 0xff, 0xff]}, [{0xff, 0x1, 0x10, [0xff, 0xff, 0xff]}], 0x10, 0x1, [0xff, 0xff]})",
},
{
"syz_test$length9(&(0x7f000001f000)={&(0x7f0000000000/0x5000)=nil, (0x0000)})",
@@ -118,6 +118,10 @@ func TestAssignSize(t *testing.T) {
"syz_test$length19(&(0x7f0000000000)={{0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0xff}, 0xff, 0xff, 0xff})",
"syz_test$length19(&(0x7f0000000000)={{0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x14}, 0x14, 0x14, 0x5})",
},
+ {
+ "syz_test$length20(&(0x7f0000000000)={{{0xff, 0xff, 0xff, 0xff}, 0xff, 0xff, 0xff}, 0xff, 0xff})",
+ "syz_test$length20(&(0x7f0000000000)={{{0x4, 0x4, 0x7, 0x9}, 0x7, 0x7, 0x9}, 0x9, 0x9})",
+ },
}
for i, test := range tests {
diff --git a/sys/README.md b/sys/README.md
index 2e5f07ec1..b5b497bc6 100644
--- a/sys/README.md
+++ b/sys/README.md
@@ -133,6 +133,36 @@ accept(fd sock, ...) sock
listen(fd sock, backlog int32)
```
+### Length
+
+You can specify length of a particular field in struct or a named argument by using `len` and `bytesize` types, for example:
+```
+write(fd fd, buf buffer[in], count len[buf]) len[buf]
+
+sock_fprog {
+ len len[filter, int16]
+ filter ptr[in, array[sock_filter]]
+}
+```
+
+If `len`'s argument is a pointer (or a `buffer`), then the length of the pointee argument is used.
+
+To denote the length of a field in N-byte words use `bytesizeN`, possible values for N are 1, 2, 4 and 8.
+
+To denote the length of the parent struct, you can use `len[parent, int8]`.
+To denote the length of the higher level parent when structs are embedded into one another, you can specify the type name of the particular parent:
+```
+struct s1 {
+ f0 len[s2] # length of s2
+}
+
+struct s2 {
+ f0 s1
+ f1 array[int32]
+}
+
+```
+
### Proc
The `proc` type can be used to denote per process integers.
diff --git a/sys/test.txt b/sys/test.txt
index e36af549d..0ce7ec819 100644
--- a/sys/test.txt
+++ b/sys/test.txt
@@ -186,6 +186,8 @@ syz_test$length17(a0 ptr[in, syz_length_bytesize2_struct])
syz_test$length18(a0 ptr[in, syz_length_bytesize3_struct])
syz_test$length19(a0 ptr[in, syz_length_bf_struct])
+syz_test$length20(a0 ptr[in, syz_length_parent2_struct])
+
syz_length_flags = 0, 1
syz_length_int_struct {
@@ -299,6 +301,26 @@ syz_length_bf_struct {
f3 bytesize4[f0, int8]
}
+syz_length_parent2_struct_inner_inner {
+ f1 len[parent, int8]
+ f2 len[syz_length_parent2_struct_inner_inner, int8]
+ f3 len[syz_length_parent2_struct_inner, int8]
+ f4 len[syz_length_parent2_struct, int8]
+}
+
+syz_length_parent2_struct_inner {
+ f0 syz_length_parent2_struct_inner_inner
+ f1 len[parent, int8]
+ f2 len[syz_length_parent2_struct_inner, int8]
+ f3 len[syz_length_parent2_struct, int8]
+}
+
+syz_length_parent2_struct {
+ f0 syz_length_parent2_struct_inner
+ f1 len[parent, int8]
+ f2 len[syz_length_parent2_struct, int8]
+}
+
# Big endian
syz_test$end0(a0 ptr[in, syz_end_int_struct])