1// Copyright 2015 syzkaller project authors. All rights reserved. 2// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4package prog 5 6import ( 7 "fmt" 8 "path/filepath" 9) 10 11var debug = false // enabled in tests 12 13func (p *Prog) debugValidate() { 14 if debug { 15 if err := p.validate(); err != nil { 16 panic(err) 17 } 18 } 19} 20 21type validCtx struct { 22 target *Target 23 args map[Arg]bool 24 uses map[Arg]Arg 25} 26 27func (p *Prog) validate() error { 28 ctx := &validCtx{ 29 target: p.Target, 30 args: make(map[Arg]bool), 31 uses: make(map[Arg]Arg), 32 } 33 for _, c := range p.Calls { 34 if c.Meta == nil { 35 return fmt.Errorf("call does not have meta information") 36 } 37 if err := ctx.validateCall(c); err != nil { 38 return fmt.Errorf("call %v: %v", c.Meta.Name, err) 39 } 40 } 41 for u, orig := range ctx.uses { 42 if !ctx.args[u] { 43 return fmt.Errorf("use of %+v referes to an out-of-tree arg\narg: %#v", orig, u) 44 } 45 } 46 return nil 47} 48 49func (ctx *validCtx) validateCall(c *Call) error { 50 if len(c.Args) != len(c.Meta.Args) { 51 return fmt.Errorf("wrong number of arguments, want %v, got %v", 52 len(c.Meta.Args), len(c.Args)) 53 } 54 for i, arg := range c.Args { 55 if err := ctx.validateArg(arg, c.Meta.Args[i]); err != nil { 56 return err 57 } 58 } 59 return ctx.validateRet(c) 60} 61 62func (ctx *validCtx) validateRet(c *Call) error { 63 if c.Meta.Ret == nil { 64 if c.Ret != nil { 65 return fmt.Errorf("return value without type") 66 } 67 return nil 68 } 69 if c.Ret == nil { 70 return fmt.Errorf("return value is absent") 71 } 72 if c.Ret.Type().Dir() != DirOut { 73 return fmt.Errorf("return value %v is not output", c.Ret) 74 } 75 if c.Ret.Res != nil || c.Ret.Val != 0 || c.Ret.OpDiv != 0 || c.Ret.OpAdd != 0 { 76 return fmt.Errorf("return value %v is not empty", c.Ret) 77 } 78 return ctx.validateArg(c.Ret, c.Meta.Ret) 79} 80 81func (ctx *validCtx) validateArg(arg Arg, typ Type) error { 82 if arg == nil { 83 return fmt.Errorf("nil arg") 84 } 85 if ctx.args[arg] { 86 return fmt.Errorf("arg %#v is referenced several times in the tree", arg) 87 } 88 if arg.Type() == nil { 89 return fmt.Errorf("no arg type") 90 } 91 if !ctx.target.isAnyPtr(arg.Type()) && arg.Type() != typ { 92 return fmt.Errorf("bad arg type %#v, expect %#v", arg.Type(), typ) 93 } 94 ctx.args[arg] = true 95 return arg.validate(ctx) 96} 97 98func (arg *ConstArg) validate(ctx *validCtx) error { 99 switch typ := arg.Type().(type) { 100 case *IntType: 101 if typ.Dir() == DirOut && !isDefault(arg) { 102 return fmt.Errorf("out int arg '%v' has bad const value %v", typ.Name(), arg.Val) 103 } 104 case *ProcType: 105 if arg.Val >= typ.ValuesPerProc && !isDefault(arg) { 106 return fmt.Errorf("per proc arg '%v' has bad value %v", typ.Name(), arg.Val) 107 } 108 case *CsumType: 109 if arg.Val != 0 { 110 return fmt.Errorf("csum arg '%v' has nonzero value %v", typ.Name(), arg.Val) 111 } 112 case *ConstType, *FlagsType, *LenType: 113 default: 114 return fmt.Errorf("const arg %v has bad type %v", arg, typ.Name()) 115 } 116 if typ := arg.Type(); typ.Dir() == DirOut { 117 // We generate output len arguments, which makes sense since it can be 118 // a length of a variable-length array which is not known otherwise. 119 if _, isLen := typ.(*LenType); !isLen { 120 if !typ.isDefaultArg(arg) { 121 return fmt.Errorf("output arg '%v'/'%v' has non default value '%+v'", 122 typ.FieldName(), typ.Name(), arg) 123 } 124 } 125 } 126 return nil 127} 128 129func (arg *ResultArg) validate(ctx *validCtx) error { 130 typ, ok := arg.Type().(*ResourceType) 131 if !ok { 132 return fmt.Errorf("result arg %v has bad type %v", arg, arg.Type().Name()) 133 } 134 for u := range arg.uses { 135 if u == nil { 136 return fmt.Errorf("nil reference in uses for arg %+v", arg) 137 } 138 if u.Res != arg { 139 return fmt.Errorf("result arg '%v' has broken uses link to (%+v)", arg, u) 140 } 141 ctx.uses[u] = arg 142 } 143 if typ.Dir() == DirOut && arg.Val != 0 && arg.Val != typ.Default() { 144 return fmt.Errorf("out resource arg '%v' has bad const value %v", typ.Name(), arg.Val) 145 } 146 if arg.Res != nil { 147 if !ctx.args[arg.Res] { 148 return fmt.Errorf("result arg %v references out-of-tree result: %#v -> %#v", 149 typ.Name(), arg, arg.Res) 150 } 151 if !arg.Res.uses[arg] { 152 return fmt.Errorf("result arg '%v' has broken link (%+v)", typ.Name(), arg.Res.uses) 153 } 154 } 155 return nil 156} 157 158func (arg *DataArg) validate(ctx *validCtx) error { 159 typ, ok := arg.Type().(*BufferType) 160 if !ok { 161 return fmt.Errorf("data arg %v has bad type %v", arg, arg.Type().Name()) 162 } 163 if typ.Dir() == DirOut && len(arg.data) != 0 { 164 return fmt.Errorf("output arg '%v' has data", typ.Name()) 165 } 166 if !typ.Varlen() && typ.Size() != arg.Size() { 167 return fmt.Errorf("data arg %v has wrong size %v, want %v", 168 typ.Name(), arg.Size(), typ.Size()) 169 } 170 switch typ.Kind { 171 case BufferString: 172 if typ.TypeSize != 0 && arg.Size() != typ.TypeSize { 173 return fmt.Errorf("string arg '%v' has size %v, which should be %v", 174 typ.Name(), arg.Size(), typ.TypeSize) 175 } 176 case BufferFilename: 177 file := string(arg.data) 178 for len(file) != 0 && file[len(file)-1] == 0 { 179 file = file[:len(file)-1] 180 } 181 file = filepath.Clean(file) 182 if len(file) > 0 && file[0] == '/' || 183 len(file) > 1 && file[0] == '.' && file[1] == '.' { 184 return fmt.Errorf("sandbox escaping file name %q", string(arg.data)) 185 } 186 } 187 return nil 188} 189 190func (arg *GroupArg) validate(ctx *validCtx) error { 191 switch typ := arg.Type().(type) { 192 case *StructType: 193 if len(arg.Inner) != len(typ.Fields) { 194 return fmt.Errorf("struct arg '%v' has wrong number of fields: want %v, got %v", 195 typ.Name(), len(typ.Fields), len(arg.Inner)) 196 } 197 for i, field := range arg.Inner { 198 if err := ctx.validateArg(field, typ.Fields[i]); err != nil { 199 return err 200 } 201 } 202 case *ArrayType: 203 if typ.Kind == ArrayRangeLen && typ.RangeBegin == typ.RangeEnd && 204 uint64(len(arg.Inner)) != typ.RangeBegin { 205 return fmt.Errorf("array %v has wrong number of elements %v, want %v", 206 typ.Name(), len(arg.Inner), typ.RangeBegin) 207 } 208 for _, elem := range arg.Inner { 209 if err := ctx.validateArg(elem, typ.Type); err != nil { 210 return err 211 } 212 } 213 default: 214 return fmt.Errorf("group arg %v has bad type %v", arg, typ.Name()) 215 } 216 return nil 217} 218 219func (arg *UnionArg) validate(ctx *validCtx) error { 220 typ, ok := arg.Type().(*UnionType) 221 if !ok { 222 return fmt.Errorf("union arg %v has bad type %v", arg, arg.Type().Name()) 223 } 224 var optType Type 225 for _, typ1 := range typ.Fields { 226 if arg.Option.Type().FieldName() == typ1.FieldName() { 227 optType = typ1 228 break 229 } 230 } 231 if optType == nil { 232 return fmt.Errorf("union arg '%v' has bad option", typ.Name()) 233 } 234 return ctx.validateArg(arg.Option, optType) 235} 236 237func (arg *PointerArg) validate(ctx *validCtx) error { 238 switch typ := arg.Type().(type) { 239 case *VmaType: 240 if arg.Res != nil { 241 return fmt.Errorf("vma arg '%v' has data", typ.Name()) 242 } 243 case *PtrType: 244 if arg.Res == nil && !arg.Type().Optional() { 245 return fmt.Errorf("non optional pointer arg '%v' is nil", typ.Name()) 246 } 247 if arg.Res != nil { 248 if err := ctx.validateArg(arg.Res, typ.Type); err != nil { 249 return err 250 } 251 } 252 if arg.VmaSize != 0 { 253 return fmt.Errorf("pointer arg '%v' has nonzero size", typ.Name()) 254 } 255 if typ.Dir() == DirOut { 256 return fmt.Errorf("pointer arg '%v' has output direction", typ.Name()) 257 } 258 default: 259 return fmt.Errorf("ptr arg %v has bad type %v", arg, typ.Name()) 260 } 261 maxMem := ctx.target.NumPages * ctx.target.PageSize 262 size := arg.VmaSize 263 if size == 0 && arg.Res != nil { 264 size = arg.Res.Size() 265 } 266 if arg.Address >= maxMem || arg.Address+size > maxMem { 267 return fmt.Errorf("ptr %v has bad address %v/%v/%v", 268 arg.Type().Name(), arg.Address, arg.VmaSize, size) 269 } 270 return nil 271} 272