diff options
| -rw-r--r-- | executor/syscalls_test.h | 10 | ||||
| -rw-r--r-- | pkg/compiler/check.go | 9 | ||||
| -rw-r--r-- | pkg/compiler/compiler.go | 50 | ||||
| -rw-r--r-- | pkg/compiler/consts.go | 4 | ||||
| -rw-r--r-- | pkg/compiler/gen.go | 16 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors2.txt | 8 | ||||
| -rw-r--r-- | prog/size_test.go | 4 | ||||
| -rw-r--r-- | sys/test/32.go | 9 | ||||
| -rw-r--r-- | sys/test/64.go | 9 | ||||
| -rw-r--r-- | sys/test/test.txt | 5 |
10 files changed, 89 insertions, 35 deletions
diff --git a/executor/syscalls_test.h b/executor/syscalls_test.h index 9468387e1..d5be16213 100644 --- a/executor/syscalls_test.h +++ b/executor/syscalls_test.h @@ -2,11 +2,11 @@ #if 0 #define GOARCH "32" -#define SYZ_REVISION "035aa7331fff3c8bb13bc8925ae43befcbc94a71" +#define SYZ_REVISION "d4cbc2aec52e291fefa8155c6c6ca397ba3c9e49" #define SYZ_PAGE_SIZE 8192 #define SYZ_NUM_PAGES 2048 #define SYZ_DATA_OFFSET 536870912 -unsigned syscall_count = 91; +unsigned syscall_count = 92; call_t syscalls[] = { {"foo$any0", 0, (syscall_t)foo}, {"foo$anyres", 0, (syscall_t)foo}, @@ -68,6 +68,7 @@ call_t syscalls[] = { {"syz_test$length25", 0, (syscall_t)syz_test}, {"syz_test$length26", 0, (syscall_t)syz_test}, {"syz_test$length27", 0, (syscall_t)syz_test}, + {"syz_test$length28", 0, (syscall_t)syz_test}, {"syz_test$length3", 0, (syscall_t)syz_test}, {"syz_test$length4", 0, (syscall_t)syz_test}, {"syz_test$length5", 0, (syscall_t)syz_test}, @@ -105,11 +106,11 @@ call_t syscalls[] = { #if 0 #define GOARCH "64" -#define SYZ_REVISION "7106e9ab2b7a52203a8ad681140f3326e8b3d7ce" +#define SYZ_REVISION "cabe73c3b49273a8b0cd13bff35d40897dd88138" #define SYZ_PAGE_SIZE 4096 #define SYZ_NUM_PAGES 4096 #define SYZ_DATA_OFFSET 536870912 -unsigned syscall_count = 91; +unsigned syscall_count = 92; call_t syscalls[] = { {"foo$any0", 0, (syscall_t)foo}, {"foo$anyres", 0, (syscall_t)foo}, @@ -171,6 +172,7 @@ call_t syscalls[] = { {"syz_test$length25", 0, (syscall_t)syz_test}, {"syz_test$length26", 0, (syscall_t)syz_test}, {"syz_test$length27", 0, (syscall_t)syz_test}, + {"syz_test$length28", 0, (syscall_t)syz_test}, {"syz_test$length3", 0, (syscall_t)syz_test}, {"syz_test$length4", 0, (syscall_t)syz_test}, {"syz_test$length5", 0, (syscall_t)syz_test}, diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 2a6afae3a..4dac37260 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -240,10 +240,11 @@ func (comp *compiler) checkAttributeValues() { switch n := decl.(type) { case *ast.Struct: for _, attr := range n.Attrs { - if !n.IsUnion && attr.Ident == "size" { + if attr.Ident == "size" { + _, typ, name := n.Info() if comp.structIsVarlen(n.Name.Name) { - comp.error(attr.Pos, "varlen struct %v has size attribute", - n.Name.Name) + comp.error(attr.Pos, "varlen %v %v has size attribute", + typ, name) } sz := attr.Args[0].Value if sz == 0 || sz > 1<<20 { @@ -906,7 +907,7 @@ func (comp *compiler) checkVarlen(n *ast.Struct) { // Non-varlen unions can't have varlen fields. // Non-packed structs can't have varlen fields in the middle. if n.IsUnion { - if varlen := comp.parseUnionAttrs(n); varlen { + if varlen, _ := comp.parseUnionAttrs(n); varlen { return } } else { diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 314cbef41..f0d1176e7 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -145,9 +145,11 @@ func (comp *compiler) structIsVarlen(name string) bool { return varlen } s := comp.structs[name] - if s.IsUnion && comp.parseUnionAttrs(s) { - comp.structVarlen[name] = true - return true + if s.IsUnion { + if varlen, _ := comp.parseUnionAttrs(s); varlen { + comp.structVarlen[name] = true + return true + } } comp.structVarlen[name] = false // to not hang on recursive types varlen := false @@ -161,18 +163,21 @@ func (comp *compiler) structIsVarlen(name string) bool { return varlen } -func (comp *compiler) parseUnionAttrs(n *ast.Struct) (varlen bool) { +func (comp *compiler) parseUnionAttrs(n *ast.Struct) (varlen bool, size uint64) { + size = sizeUnassigned for _, attr := range n.Attrs { switch attr.Ident { case "varlen": + if len(attr.Args) != 0 { + comp.error(attr.Pos, "%v attribute has args", attr.Ident) + } varlen = true + case "size": + size = comp.parseSizeAttr(n, attr) default: comp.error(attr.Pos, "unknown union %v attribute %v", n.Name.Name, attr.Ident) } - if len(attr.Args) != 0 { - comp.error(attr.Pos, "%v attribute has args", attr.Ident) - } } return } @@ -207,19 +212,7 @@ func (comp *compiler) parseStructAttrs(n *ast.Struct) (packed bool, size, align } align = a case attr.Ident == "size": - if len(attr.Args) != 1 { - comp.error(attr.Pos, "%v attribute is expected to have 1 argument", attr.Ident) - } - sz := attr.Args[0] - if unexpected, _, ok := checkTypeKind(sz, kindInt); !ok { - comp.error(sz.Pos, "unexpected %v, expect int", unexpected) - return - } - if sz.HasColon || len(sz.Args) != 0 { - comp.error(sz.Pos, "size attribute has colon or args") - return - } - size = sz.Value + size = comp.parseSizeAttr(n, attr) default: comp.error(attr.Pos, "unknown struct %v attribute %v", n.Name.Name, attr.Ident) @@ -228,6 +221,23 @@ func (comp *compiler) parseStructAttrs(n *ast.Struct) (packed bool, size, align return } +func (comp *compiler) parseSizeAttr(n *ast.Struct, attr *ast.Type) uint64 { + if len(attr.Args) != 1 { + comp.error(attr.Pos, "%v attribute is expected to have 1 argument", attr.Ident) + return sizeUnassigned + } + sz := attr.Args[0] + if unexpected, _, ok := checkTypeKind(sz, kindInt); !ok { + comp.error(sz.Pos, "unexpected %v, expect int", unexpected) + return sizeUnassigned + } + if sz.HasColon || len(sz.Args) != 0 { + comp.error(sz.Pos, "size attribute has colon or args") + return sizeUnassigned + } + return sz.Value +} + func (comp *compiler) getTypeDesc(t *ast.Type) *typeDesc { if desc := builtinTypes[t.Ident]; desc != nil { return desc diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go index 789674578..1b008bd4f 100644 --- a/pkg/compiler/consts.go +++ b/pkg/compiler/consts.go @@ -87,7 +87,7 @@ func (comp *compiler) extractConsts() map[string]*ConstInfo { switch n := decl.(type) { case *ast.Struct: for _, attr := range n.Attrs { - if !n.IsUnion && attr.Ident == "size" { + if attr.Ident == "size" { info := getConstInfo(infos, attr.Pos) info.consts[attr.Args[0].Ident] = true } @@ -199,7 +199,7 @@ func (comp *compiler) patchConsts(consts map[string]uint64) { } if n, ok := decl.(*ast.Struct); ok { for _, attr := range n.Attrs { - if !n.IsUnion && attr.Ident == "size" { + if attr.Ident == "size" { sz := attr.Args[0] comp.patchIntConst(sz.Pos, &sz.Value, &sz.Ident, consts, &missing) diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index 74d1b5d78..5bf239e79 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -165,14 +165,24 @@ func (comp *compiler) genStructDescs(syscalls []*prog.Syscall) []*prog.KeyedStru if !checkStruct(t.Key, &t.StructDesc) { return } + structNode := comp.structNodes[t.StructDesc] + varlen, sizeAttr := comp.parseUnionAttrs(structNode) t.TypeSize = 0 - varlen := comp.parseUnionAttrs(comp.structNodes[t.StructDesc]) if !varlen { for _, fld := range t.Fields { - if t.TypeSize < fld.Size() { - t.TypeSize = fld.Size() + sz := fld.Size() + if sizeAttr != sizeUnassigned && sz > sizeAttr { + comp.error(structNode.Pos, "union %v has size attribute %v"+ + " which is less than field %v size %v", + structNode.Name.Name, sizeAttr, fld.Name(), sz) + } + if t.TypeSize < sz { + t.TypeSize = sz } } + if sizeAttr != sizeUnassigned { + t.TypeSize = sizeAttr + } } } } diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt index a8d29789a..86148a563 100644 --- a/pkg/compiler/testdata/errors2.txt +++ b/pkg/compiler/testdata/errors2.txt @@ -91,6 +91,14 @@ u1 [ f2 len[f1, int32] ### len target f1 does not exist ] +u2 [ + f1 int8 +] [size[0]] ### size attribute has bad value 0, expect [1, 1<<20] + +u3 [ + f1 int8 +] [varlen, size[8]] ### varlen union u3 has size attribute + foo$200(a ptr[in, s2]) foo$201(a ptr[in, s1]) foo$202(a u1) diff --git a/prog/size_test.go b/prog/size_test.go index f5ac9a958..08b7cba92 100644 --- a/prog/size_test.go +++ b/prog/size_test.go @@ -142,6 +142,10 @@ func TestAssignSize(t *testing.T) { "syz_test$length27(&(0x7f0000000000), 0x0)", "syz_test$length27(&(0x7f0000000000), 0x2a)", }, + { + "syz_test$length28(&(0x7f0000000000), 0x0)", + "syz_test$length28(&(0x7f0000000000)=@f1, 0x2a)", + }, } for i, test := range tests { diff --git a/sys/test/32.go b/sys/test/32.go index 2afb57717..7425c8bd9 100644 --- a/sys/test/32.go +++ b/sys/test/32.go @@ -54,6 +54,9 @@ var structDescs_32 = []*KeyedStruct{ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}}, &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 41}}, IsPad: true}, }}}, + {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_nontemp4"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_nontemp4", TypeSize: 4}, Fields: []Type{ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "f1", TypeSize: 4}}, Buf: "len_temp3"}, }}}, @@ -683,6 +686,10 @@ var syscalls_32 = []*Syscall{ &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 4}, Type: &StructType{Key: StructKey{Name: "explicitly_sized"}}}, &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "a1", TypeSize: 4}}, Buf: "a0"}, }}, + {Name: "syz_test$length28", CallName: "syz_test", Args: []Type{ + &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 4}, Type: &UnionType{Key: StructKey{Name: "explicitly_sized_union"}}}, + &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "a1", TypeSize: 4}}, Buf: "a0"}, + }}, {Name: "syz_test$length3", CallName: "syz_test", Args: []Type{ &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 4}, Type: &StructType{Key: StructKey{Name: "syz_length_len_struct"}}}, }}, @@ -790,4 +797,4 @@ var consts_32 = []ConstValue{ {Name: "ONLY_32BITS_CONST", Value: 1}, } -const revision_32 = "035aa7331fff3c8bb13bc8925ae43befcbc94a71" +const revision_32 = "d4cbc2aec52e291fefa8155c6c6ca397ba3c9e49" diff --git a/sys/test/64.go b/sys/test/64.go index ac32ebbe8..4b48d9b05 100644 --- a/sys/test/64.go +++ b/sys/test/64.go @@ -54,6 +54,9 @@ var structDescs_64 = []*KeyedStruct{ &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}}, &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 41}}, IsPad: true}, }}}, + {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_nontemp4"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_nontemp4", TypeSize: 4}, Fields: []Type{ &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "f1", TypeSize: 4}}, Buf: "len_temp3"}, }}}, @@ -682,6 +685,10 @@ var syscalls_64 = []*Syscall{ &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 8}, Type: &StructType{Key: StructKey{Name: "explicitly_sized"}}}, &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "a1", TypeSize: 8}}, Buf: "a0"}, }}, + {Name: "syz_test$length28", CallName: "syz_test", Args: []Type{ + &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 8}, Type: &UnionType{Key: StructKey{Name: "explicitly_sized_union"}}}, + &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "a1", TypeSize: 8}}, Buf: "a0"}, + }}, {Name: "syz_test$length3", CallName: "syz_test", Args: []Type{ &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 8}, Type: &StructType{Key: StructKey{Name: "syz_length_len_struct"}}}, }}, @@ -788,4 +795,4 @@ var consts_64 = []ConstValue{ {Name: "IPPROTO_UDP", Value: 17}, } -const revision_64 = "7106e9ab2b7a52203a8ad681140f3326e8b3d7ce" +const revision_64 = "cabe73c3b49273a8b0cd13bff35d40897dd88138" diff --git a/sys/test/test.txt b/sys/test/test.txt index 063a9a2e2..ca548d073 100644 --- a/sys/test/test.txt +++ b/sys/test/test.txt @@ -405,10 +405,15 @@ explicitly_sized { f1 int8 } [size[42]] +explicitly_sized_union [ + f1 int8 +] [size[42]] + syz_test$length24(a ptr[in, len_nontemp5]) syz_test$length25(a0 ptr[in, array[array[int8]]], a1 len[a0]) syz_test$length26(a ptr[in, len_unaligned], b bytesize[a]) syz_test$length27(a0 ptr[in, explicitly_sized], a1 len[a0]) +syz_test$length28(a0 ptr[in, explicitly_sized_union], a1 len[a0]) # Big endian |
