// Copyright 2015/2016 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" ) type Syscall struct { ID int NR uint64 // kernel syscall number Name string CallName string Args []Type Ret Type } type Dir int const ( DirIn Dir = iota DirOut DirInOut ) func (dir Dir) String() string { switch dir { case DirIn: return "in" case DirOut: return "out" case DirInOut: return "inout" default: panic("unknown dir") } } type BinaryFormat int const ( FormatNative BinaryFormat = iota FormatBigEndian FormatStrDec FormatStrHex FormatStrOct ) type Type interface { String() string Name() string FieldName() string Dir() Dir Optional() bool Varlen() bool Size() uint64 Format() BinaryFormat BitfieldOffset() uint64 BitfieldLength() uint64 BitfieldMiddle() bool // returns true for all but last bitfield in a group makeDefaultArg() Arg isDefaultArg(arg Arg) bool generate(r *randGen, s *state) (arg Arg, calls []*Call) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool } func IsPad(t Type) bool { if ct, ok := t.(*ConstType); ok && ct.IsPad { return true } return false } type TypeCommon struct { TypeName string FldName string // for struct fields and named args TypeSize uint64 // static size of the type, or 0 for variable size types ArgDir Dir IsOptional bool IsVarlen bool } func (t *TypeCommon) Name() string { return t.TypeName } func (t *TypeCommon) FieldName() string { return t.FldName } func (t *TypeCommon) Optional() bool { return t.IsOptional } func (t *TypeCommon) Size() uint64 { if t.IsVarlen { panic(fmt.Sprintf("static type size is not known: %#v", t)) } return t.TypeSize } func (t *TypeCommon) Varlen() bool { return t.IsVarlen } func (t *TypeCommon) Format() BinaryFormat { return FormatNative } func (t *TypeCommon) BitfieldOffset() uint64 { return 0 } func (t *TypeCommon) BitfieldLength() uint64 { return 0 } func (t *TypeCommon) BitfieldMiddle() bool { return false } func (t TypeCommon) Dir() Dir { return t.ArgDir } type ResourceDesc struct { Name string Type Type Kind []string Values []uint64 } type ResourceType struct { TypeCommon ArgFormat BinaryFormat Desc *ResourceDesc } func (t *ResourceType) String() string { return t.Name() } func (t *ResourceType) makeDefaultArg() Arg { return MakeResultArg(t, nil, t.Default()) } func (t *ResourceType) isDefaultArg(arg Arg) bool { a := arg.(*ResultArg) return a.Res == nil && a.OpDiv == 0 && a.OpAdd == 0 && len(a.uses) == 0 && a.Val == t.Default() } func (t *ResourceType) Default() uint64 { return t.Desc.Values[0] } func (t *ResourceType) SpecialValues() []uint64 { return t.Desc.Values } func (t *ResourceType) Format() BinaryFormat { return t.ArgFormat } type IntTypeCommon struct { TypeCommon ArgFormat BinaryFormat BitfieldOff uint64 BitfieldLen uint64 BitfieldMdl bool } func (t *IntTypeCommon) String() string { return t.Name() } func (t *IntTypeCommon) Format() BinaryFormat { return t.ArgFormat } func (t *IntTypeCommon) BitfieldOffset() uint64 { return t.BitfieldOff } func (t *IntTypeCommon) BitfieldLength() uint64 { return t.BitfieldLen } func (t *IntTypeCommon) BitfieldMiddle() bool { return t.BitfieldMdl } type ConstType struct { IntTypeCommon Val uint64 IsPad bool } func (t *ConstType) makeDefaultArg() Arg { return MakeConstArg(t, t.Val) } func (t *ConstType) isDefaultArg(arg Arg) bool { return arg.(*ConstArg).Val == t.Val } func (t *ConstType) String() string { if t.IsPad { return fmt.Sprintf("pad[%v]", t.Size()) } return fmt.Sprintf("const[%v, %v]", t.Val, t.IntTypeCommon.String()) } type IntKind int const ( IntPlain IntKind = iota IntFileoff // offset within a file IntRange ) type IntType struct { IntTypeCommon Kind IntKind RangeBegin uint64 RangeEnd uint64 } func (t *IntType) makeDefaultArg() Arg { return MakeConstArg(t, 0) } func (t *IntType) isDefaultArg(arg Arg) bool { return arg.(*ConstArg).Val == 0 } type FlagsType struct { IntTypeCommon Vals []uint64 BitMask bool } func (t *FlagsType) makeDefaultArg() Arg { return MakeConstArg(t, 0) } func (t *FlagsType) isDefaultArg(arg Arg) bool { return arg.(*ConstArg).Val == 0 } type LenType struct { IntTypeCommon BitSize uint64 // want size in multiple of bits instead of array size Buf string } func (t *LenType) makeDefaultArg() Arg { return MakeConstArg(t, 0) } func (t *LenType) isDefaultArg(arg Arg) bool { return arg.(*ConstArg).Val == 0 } type ProcType struct { IntTypeCommon ValuesStart uint64 ValuesPerProc uint64 } const ( MaxPids = 32 procDefaultValue = 0xffffffffffffffff // special value denoting 0 for all procs ) func (t *ProcType) makeDefaultArg() Arg { return MakeConstArg(t, procDefaultValue) } func (t *ProcType) isDefaultArg(arg Arg) bool { return arg.(*ConstArg).Val == procDefaultValue } type CsumKind int const ( CsumInet CsumKind = iota CsumPseudo ) type CsumType struct { IntTypeCommon Kind CsumKind Buf string Protocol uint64 // for CsumPseudo } func (t *CsumType) String() string { return "csum" } func (t *CsumType) makeDefaultArg() Arg { return MakeConstArg(t, 0) } func (t *CsumType) isDefaultArg(arg Arg) bool { return arg.(*ConstArg).Val == 0 } type VmaType struct { TypeCommon RangeBegin uint64 // in pages RangeEnd uint64 } func (t *VmaType) String() string { return "vma" } func (t *VmaType) makeDefaultArg() Arg { return MakeNullPointerArg(t) } func (t *VmaType) isDefaultArg(arg Arg) bool { return arg.(*PointerArg).IsNull() } type BufferKind int const ( BufferBlobRand BufferKind = iota BufferBlobRange BufferString BufferFilename BufferText ) type TextKind int const ( TextX86Real TextKind = iota TextX86bit16 TextX86bit32 TextX86bit64 TextArm64 ) type BufferType struct { TypeCommon Kind BufferKind RangeBegin uint64 // for BufferBlobRange kind RangeEnd uint64 // for BufferBlobRange kind Text TextKind // for BufferText SubKind string Values []string // possible values for BufferString kind NoZ bool // non-zero terminated BufferString/BufferFilename } func (t *BufferType) String() string { return "buffer" } func (t *BufferType) makeDefaultArg() Arg { if t.Dir() == DirOut { var sz uint64 if !t.Varlen() { sz = t.Size() } return MakeOutDataArg(t, sz) } var data []byte if !t.Varlen() { data = make([]byte, t.Size()) } return MakeDataArg(t, data) } func (t *BufferType) isDefaultArg(arg Arg) bool { a := arg.(*DataArg) if a.Size() == 0 { return true } if a.Type().Varlen() { return false } if a.Type().Dir() == DirOut { return true } for _, v := range a.Data() { if v != 0 { return false } } return true } type ArrayKind int const ( ArrayRandLen ArrayKind = iota ArrayRangeLen ) type ArrayType struct { TypeCommon Type Type Kind ArrayKind RangeBegin uint64 RangeEnd uint64 } func (t *ArrayType) String() string { return fmt.Sprintf("array[%v]", t.Type.String()) } func (t *ArrayType) makeDefaultArg() Arg { var elems []Arg if t.Kind == ArrayRangeLen && t.RangeBegin == t.RangeEnd { for i := uint64(0); i < t.RangeBegin; i++ { elems = append(elems, t.Type.makeDefaultArg()) } } return MakeGroupArg(t, elems) } func (t *ArrayType) isDefaultArg(arg Arg) bool { a := arg.(*GroupArg) if !a.fixedInnerSize() && len(a.Inner) != 0 { return false } for _, elem := range a.Inner { if !isDefault(elem) { return false } } return true } type PtrType struct { TypeCommon Type Type } func (t *PtrType) String() string { return fmt.Sprintf("ptr[%v, %v]", t.Dir(), t.Type.String()) } func (t *PtrType) makeDefaultArg() Arg { if t.Optional() { return MakeNullPointerArg(t) } return MakePointerArg(t, 0, t.Type.makeDefaultArg()) } func (t *PtrType) isDefaultArg(arg Arg) bool { a := arg.(*PointerArg) if t.Optional() { return a.IsNull() } return a.Address == 0 && isDefault(a.Res) } type StructType struct { Key StructKey FldName string *StructDesc } func (t *StructType) String() string { return t.Name() } func (t *StructType) FieldName() string { return t.FldName } func (t *StructType) makeDefaultArg() Arg { inner := make([]Arg, len(t.Fields)) for i, field := range t.Fields { inner[i] = field.makeDefaultArg() } return MakeGroupArg(t, inner) } func (t *StructType) isDefaultArg(arg Arg) bool { a := arg.(*GroupArg) for _, elem := range a.Inner { if !isDefault(elem) { return false } } return true } type UnionType struct { Key StructKey FldName string *StructDesc } func (t *UnionType) String() string { return t.Name() } func (t *UnionType) FieldName() string { return t.FldName } func (t *UnionType) makeDefaultArg() Arg { return MakeUnionArg(t, t.Fields[0].makeDefaultArg()) } func (t *UnionType) isDefaultArg(arg Arg) bool { a := arg.(*UnionArg) return a.Option.Type().FieldName() == t.Fields[0].FieldName() && isDefault(a.Option) } type StructDesc struct { TypeCommon Fields []Type AlignAttr uint64 } func (t *StructDesc) FieldName() string { panic("must not be called") } type StructKey struct { Name string Dir Dir } type KeyedStruct struct { Key StructKey Desc *StructDesc } type ConstValue struct { Name string Value uint64 } func ForeachType(meta *Syscall, f func(Type)) { seen := make(map[*StructDesc]bool) var rec func(t Type) rec = func(t Type) { f(t) switch a := t.(type) { case *PtrType: rec(a.Type) case *ArrayType: rec(a.Type) case *StructType: if seen[a.StructDesc] { return // prune recursion via pointers to structs/unions } seen[a.StructDesc] = true for _, f := range a.Fields { rec(f) } case *UnionType: if seen[a.StructDesc] { return // prune recursion via pointers to structs/unions } seen[a.StructDesc] = true for _, opt := range a.Fields { rec(opt) } case *ResourceType, *BufferType, *VmaType, *LenType, *FlagsType, *ConstType, *IntType, *ProcType, *CsumType: default: panic("unknown type") } } for _, t := range meta.Args { rec(t) } if meta.Ret != nil { rec(meta.Ret) } }