mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-28 13:50:52 +00:00
Merge pull request #113 from xairy/parent-parent
Make it possible to specify length of parent of parent
This commit is contained in:
commit
bb1ff0b559
@ -205,7 +205,7 @@ loop:
|
||||
if bfOff == 0 && bfLen == 0 {
|
||||
fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = (uint%v_t)0x%x);\n", size*8, addr, size*8, arg)
|
||||
} else {
|
||||
fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v_t, %v, %v, %v, %v));\n", size*8, addr, arg, bfOff, bfLen)
|
||||
fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v_t, 0x%x, 0x%x, %v, %v));\n", size*8, addr, arg, bfOff, bfLen)
|
||||
}
|
||||
case prog.ExecArgResult:
|
||||
fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n", size*8, addr, resultRef())
|
||||
|
@ -174,18 +174,14 @@ 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
|
||||
}
|
||||
argsMap[arg.Type.Name()] = arg
|
||||
argsMap[arg.Type.FieldName()] = arg
|
||||
}
|
||||
|
||||
// Fill in size arguments.
|
||||
@ -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.Name(), 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) {
|
||||
|
@ -108,7 +108,7 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) {
|
||||
}
|
||||
buf.Write([]byte{delims[1]})
|
||||
case ArgUnion:
|
||||
fmt.Fprintf(buf, "@%v=", a.OptionType.Name())
|
||||
fmt.Fprintf(buf, "@%v=", a.OptionType.FieldName())
|
||||
a.Option.serialize(buf, vars, varSeq)
|
||||
default:
|
||||
panic("unknown arg kind")
|
||||
@ -318,7 +318,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
|
||||
p.Parse('=')
|
||||
var optType sys.Type
|
||||
for _, t2 := range t1.Options {
|
||||
if name == t2.Name() {
|
||||
if name == t2.FieldName() {
|
||||
optType = t2
|
||||
break
|
||||
}
|
||||
|
@ -184,8 +184,12 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
|
||||
}
|
||||
case *sys.UnionType:
|
||||
optType := a.Options[r.Intn(len(a.Options))]
|
||||
for optType.Name() == arg.OptionType.Name() {
|
||||
maxIters := 1000
|
||||
for i := 0; optType.FieldName() == arg.OptionType.FieldName(); i++ {
|
||||
optType = a.Options[r.Intn(len(a.Options))]
|
||||
if i >= maxIters {
|
||||
panic(fmt.Sprintf("couldn't generate a different union option after %v iterations, type: %+v", maxIters, a))
|
||||
}
|
||||
}
|
||||
p.removeArg(c, arg.Option)
|
||||
opt, calls := r.generateArg(s, optType)
|
||||
@ -303,7 +307,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred func(*Prog, int) bool, crash bool)
|
||||
|
||||
var rec func(p *Prog, call *Call, arg *Arg, path string) bool
|
||||
rec = func(p *Prog, call *Call, arg *Arg, path string) bool {
|
||||
path += fmt.Sprintf("-%v", arg.Type.Name())
|
||||
path += fmt.Sprintf("-%v", arg.Type.FieldName())
|
||||
switch typ := arg.Type.(type) {
|
||||
case *sys.StructType:
|
||||
for _, innerArg := range arg.Inner {
|
||||
@ -438,7 +442,7 @@ func (p *Prog) TrimAfter(idx int) {
|
||||
}
|
||||
|
||||
func mutationArgs(c *Call) (args, bases []*Arg) {
|
||||
foreachArg(c, func(arg, base *Arg, parent *[]*Arg) {
|
||||
foreachArg(c, func(arg, base *Arg, _ *[]*Arg) {
|
||||
switch typ := arg.Type.(type) {
|
||||
case *sys.StructType:
|
||||
if isSpecialStruct(typ) == nil {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -59,6 +59,9 @@ func (c *Call) validate(ctx *validCtx) error {
|
||||
if arg.Type.Name() != typ.Name() {
|
||||
return fmt.Errorf("syscall %v: type name mismatch: %v vs %v", c.Meta.Name, arg.Type.Name(), typ.Name())
|
||||
}
|
||||
if arg.Type.FieldName() != typ.FieldName() {
|
||||
return fmt.Errorf("syscall %v: field name mismatch: %v vs %v", c.Meta.Name, arg.Type.FieldName(), typ.FieldName())
|
||||
}
|
||||
if arg.Type.Dir() == sys.DirOut {
|
||||
if (arg.Val != 0 && arg.Val != arg.Type.Default()) || arg.AddrPage != 0 || arg.AddrOffset != 0 {
|
||||
// We generate output len arguments, which makes sense
|
||||
|
@ -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.
|
||||
|
@ -29,6 +29,7 @@ const (
|
||||
|
||||
type Type interface {
|
||||
Name() string
|
||||
FieldName() string
|
||||
Dir() Dir
|
||||
Optional() bool
|
||||
Default() uintptr
|
||||
@ -49,6 +50,7 @@ func IsPad(t Type) bool {
|
||||
|
||||
type TypeCommon struct {
|
||||
TypeName string
|
||||
FldName string // for struct fields and named args
|
||||
ArgDir Dir
|
||||
IsOptional bool
|
||||
}
|
||||
@ -57,6 +59,10 @@ func (t *TypeCommon) Name() string {
|
||||
return t.TypeName
|
||||
}
|
||||
|
||||
func (t *TypeCommon) FieldName() string {
|
||||
return t.FldName
|
||||
}
|
||||
|
||||
func (t *TypeCommon) Optional() bool {
|
||||
return t.IsOptional
|
||||
}
|
||||
|
22
sys/test.txt
22
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])
|
||||
|
@ -265,10 +265,6 @@ func generateStructEntry(str Struct, key structKey, out io.Writer) {
|
||||
if str.IsUnion {
|
||||
typ = "UnionType"
|
||||
}
|
||||
name := key.field
|
||||
if name == "" {
|
||||
name = key.name
|
||||
}
|
||||
packed := ""
|
||||
if str.Packed {
|
||||
packed = ", packed: true"
|
||||
@ -281,8 +277,8 @@ func generateStructEntry(str Struct, key structKey, out io.Writer) {
|
||||
if str.Align != 0 {
|
||||
align = fmt.Sprintf(", align: %v", str.Align)
|
||||
}
|
||||
fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", ArgDir: %v, IsOptional: %v} %v %v %v},\n",
|
||||
key, typ, name, fmtDir(key.dir), false, packed, align, varlen)
|
||||
fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", FldName: \"%v\", ArgDir: %v, IsOptional: %v} %v %v %v},\n",
|
||||
key, typ, key.name, key.field, fmtDir(key.dir), false, packed, align, varlen)
|
||||
}
|
||||
|
||||
func generateStructFields(str Struct, key structKey, desc *Description, consts map[string]uint64, out io.Writer) {
|
||||
@ -379,7 +375,7 @@ func generateArg(
|
||||
}
|
||||
}
|
||||
common := func() string {
|
||||
return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: %v, ArgDir: %v, IsOptional: %v}", name, fmtDir(dir), opt)
|
||||
return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: \"%v\", FldName: %v, ArgDir: %v, IsOptional: %v}", typ, name, fmtDir(dir), opt)
|
||||
}
|
||||
intCommon := func(typeSize uint64, bigEndian bool, bitfieldLen uint64) string {
|
||||
// BitfieldOff and BitfieldLst will be filled in in initAlign().
|
||||
|
Loading…
Reference in New Issue
Block a user