// Copyright 2017 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. package prog import ( "fmt" "strings" ) func (target *Target) generateSize(arg Arg, lenType *LenType) uint64 { if arg == nil { // Arg is an optional pointer, set size to 0. return 0 } bitSize := lenType.BitSize if bitSize == 0 { bitSize = 8 } switch arg.Type().(type) { case *VmaType: a := arg.(*PointerArg) return a.VmaSize * 8 / bitSize case *ArrayType: a := arg.(*GroupArg) if lenType.BitSize != 0 { return a.Size() * 8 / bitSize } else { return uint64(len(a.Inner)) } default: return arg.Size() * 8 / bitSize } } func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg) { // Create a map from field names to args. argsMap := make(map[string]Arg) for _, arg := range args { if IsPad(arg.Type()) { continue } argsMap[arg.Type().FieldName()] = arg } // Fill in size arguments. for _, arg := range args { if arg = InnerArg(arg); arg == nil { continue // Pointer to optional len field, no need to fill in value. } if typ, ok := arg.Type().(*LenType); ok { a := arg.(*ConstArg) buf, ok := argsMap[typ.Buf] if ok { a.Val = target.generateSize(InnerArg(buf), typ) continue } if typ.Buf == "parent" { a.Val = parentsMap[arg].Size() if typ.BitSize != 0 { a.Val = a.Val * 8 / typ.BitSize } continue } sizeAssigned := false for parent := parentsMap[arg]; parent != nil; parent = parentsMap[parent] { parentName := parent.Type().Name() if pos := strings.IndexByte(parentName, '['); pos != -1 { // For template parents, strip arguments. parentName = parentName[:pos] } if typ.Buf == parentName { a.Val = parent.Size() if typ.BitSize != 0 { a.Val = a.Val * 8 / typ.BitSize } sizeAssigned = true break } } if sizeAssigned { continue } panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v", typ.FieldName(), typ.Buf, argsMap)) } } } func (target *Target) assignSizesArray(args []Arg) { parentsMap := make(map[Arg]Arg) for _, arg := range args { ForeachSubArg(arg, func(arg Arg, _ *ArgCtx) { if _, ok := arg.Type().(*StructType); ok { for _, field := range arg.(*GroupArg).Inner { parentsMap[InnerArg(field)] = arg } } }) } target.assignSizes(args, parentsMap) for _, arg := range args { ForeachSubArg(arg, func(arg Arg, _ *ArgCtx) { if _, ok := arg.Type().(*StructType); ok { target.assignSizes(arg.(*GroupArg).Inner, parentsMap) } }) } } func (target *Target) assignSizesCall(c *Call) { target.assignSizesArray(c.Args) } func (r *randGen) mutateSize(arg *ConstArg, parent []Arg) bool { typ := arg.Type().(*LenType) elemSize := typ.BitSize / 8 if elemSize == 0 { elemSize = 1 for _, field := range parent { if typ.Buf != field.Type().FieldName() { continue } if inner := InnerArg(field); inner != nil { switch targetType := inner.Type().(type) { case *VmaType: return false case *ArrayType: if targetType.Type.Varlen() { return false } elemSize = targetType.Type.Size() } } break } } if r.oneOf(100) { arg.Val = r.rand64() return true } if r.bin() { // Small adjustment to trigger missed size checks. if arg.Val != 0 && r.bin() { arg.Val = r.randRangeInt(0, arg.Val-1) } else { arg.Val = r.randRangeInt(arg.Val+1, arg.Val+1000) } return true } // Try to provoke int overflows. max := ^uint64(0) if r.oneOf(3) { max = 1<<32 - 1 if r.oneOf(2) { max = 1<<16 - 1 if r.oneOf(2) { max = 1<<8 - 1 } } } n := max / elemSize delta := uint64(1000 - r.biasedRand(1000, 10)) if elemSize == 1 || r.oneOf(10) { n -= delta } else { n += delta } arg.Val = n return true }