github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/prog.go (about) 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 4 package prog 5 6 import ( 7 "fmt" 8 "reflect" 9 ) 10 11 type Prog struct { 12 Target *Target 13 Calls []*Call 14 Comments []string 15 16 // Was deserialized using Unsafe mode, so can do unsafe things. 17 isUnsafe bool 18 } 19 20 func (p *Prog) CallName(call int) string { 21 if call >= len(p.Calls) || call < -1 { 22 panic(fmt.Sprintf("bad call index %v/%v", call, len(p.Calls))) 23 } 24 if call == -1 { 25 return ".extra" 26 } 27 return p.Calls[call].Meta.Name 28 } 29 30 // These properties are parsed and serialized according to the tag and the type 31 // of the corresponding fields. 32 // IMPORTANT: keep the exact values of "key" tag for existing props unchanged, 33 // otherwise the backwards compatibility would be broken. 34 type CallProps struct { 35 FailNth int `key:"fail_nth"` 36 Async bool `key:"async"` 37 Rerun int `key:"rerun"` 38 } 39 40 type Call struct { 41 Meta *Syscall 42 Args []Arg 43 Ret *ResultArg 44 Props CallProps 45 Comment string 46 } 47 48 func MakeCall(meta *Syscall, args []Arg) *Call { 49 return &Call{ 50 Meta: meta, 51 Args: args, 52 Ret: MakeReturnArg(meta.Ret), 53 } 54 } 55 56 type Arg interface { 57 Type() Type 58 Dir() Dir 59 Size() uint64 60 61 validate(ctx *validCtx, dir Dir) error 62 serialize(ctx *serializer) 63 } 64 65 type ArgCommon struct { 66 ref Ref 67 dir Dir 68 } 69 70 func (arg ArgCommon) Type() Type { 71 if arg.ref == 0 { 72 panic("broken type ref") 73 } 74 return typeRefs.Load().([]Type)[arg.ref] 75 } 76 77 func (arg *ArgCommon) Dir() Dir { 78 return arg.dir 79 } 80 81 // Used for ConstType, IntType, FlagsType, LenType, ProcType and CsumType. 82 type ConstArg struct { 83 ArgCommon 84 Val uint64 85 } 86 87 func MakeConstArg(t Type, dir Dir, v uint64) *ConstArg { 88 return &ConstArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Val: v} 89 } 90 91 func (arg *ConstArg) Size() uint64 { 92 return arg.Type().Size() 93 } 94 95 // Value returns value and pid stride. 96 func (arg *ConstArg) Value() (uint64, uint64) { 97 switch typ := (*arg).Type().(type) { 98 case *IntType: 99 return arg.Val, 0 100 case *ConstType: 101 return arg.Val, 0 102 case *FlagsType: 103 return arg.Val, 0 104 case *LenType: 105 return arg.Val, 0 106 case *ResourceType: 107 return arg.Val, 0 108 case *CsumType: 109 // Checksums are computed dynamically in executor. 110 return 0, 0 111 case *ProcType: 112 if arg.Val == procDefaultValue { 113 return 0, 0 114 } 115 return typ.ValuesStart + arg.Val, typ.ValuesPerProc 116 default: 117 panic(fmt.Sprintf("unknown ConstArg type %#v", typ)) 118 } 119 } 120 121 // Used for PtrType and VmaType. 122 type PointerArg struct { 123 ArgCommon 124 Address uint64 125 VmaSize uint64 // size of the referenced region for vma args 126 Res Arg // pointee (nil for vma) 127 } 128 129 func MakePointerArg(t Type, dir Dir, addr uint64, data Arg) *PointerArg { 130 if data == nil { 131 panic("nil pointer data arg") 132 } 133 return &PointerArg{ 134 ArgCommon: ArgCommon{ref: t.ref(), dir: DirIn}, // pointers are always in 135 Address: addr, 136 Res: data, 137 } 138 } 139 140 func MakeVmaPointerArg(t Type, dir Dir, addr, size uint64) *PointerArg { 141 if addr%1024 != 0 { 142 panic("unaligned vma address") 143 } 144 return &PointerArg{ 145 ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, 146 Address: addr, 147 VmaSize: size, 148 } 149 } 150 151 func MakeSpecialPointerArg(t Type, dir Dir, index uint64) *PointerArg { 152 if index >= maxSpecialPointers { 153 panic("bad special pointer index") 154 } 155 if _, ok := t.(*PtrType); ok { 156 dir = DirIn // pointers are always in 157 } 158 return &PointerArg{ 159 ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, 160 Address: -index, 161 } 162 } 163 164 func (arg *PointerArg) Size() uint64 { 165 return arg.Type().Size() 166 } 167 168 func (arg *PointerArg) IsSpecial() bool { 169 return arg.VmaSize == 0 && arg.Res == nil && -arg.Address < maxSpecialPointers 170 } 171 172 func (target *Target) PhysicalAddr(arg *PointerArg) uint64 { 173 if arg.IsSpecial() { 174 return target.SpecialPointers[-arg.Address] 175 } 176 return target.DataOffset + arg.Address 177 } 178 179 // Used for BufferType. 180 type DataArg struct { 181 ArgCommon 182 data []byte // for in/inout args 183 size uint64 // for out Args 184 } 185 186 func MakeDataArg(t Type, dir Dir, data []byte) *DataArg { 187 if dir == DirOut { 188 panic("non-empty output data arg") 189 } 190 return &DataArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, data: append([]byte{}, data...)} 191 } 192 193 func MakeOutDataArg(t Type, dir Dir, size uint64) *DataArg { 194 if dir != DirOut { 195 panic("empty input data arg") 196 } 197 return &DataArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, size: size} 198 } 199 200 func (arg *DataArg) Size() uint64 { 201 if len(arg.data) != 0 { 202 return uint64(len(arg.data)) 203 } 204 return arg.size 205 } 206 207 func (arg *DataArg) Data() []byte { 208 if arg.Dir() == DirOut { 209 panic("getting data of output data arg") 210 } 211 return arg.data 212 } 213 214 func (arg *DataArg) SetData(data []byte) { 215 if arg.Dir() == DirOut { 216 panic("setting data of output data arg") 217 } 218 arg.data = append([]byte{}, data...) 219 } 220 221 // Used for StructType and ArrayType. 222 // Logical group of args (struct or array). 223 type GroupArg struct { 224 ArgCommon 225 Inner []Arg 226 } 227 228 func MakeGroupArg(t Type, dir Dir, inner []Arg) *GroupArg { 229 return &GroupArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Inner: inner} 230 } 231 232 func (arg *GroupArg) Size() uint64 { 233 typ0 := arg.Type() 234 if !typ0.Varlen() { 235 return typ0.Size() 236 } 237 switch typ := typ0.(type) { 238 case *StructType: 239 var size, offset uint64 240 for i, fld := range arg.Inner { 241 if i == typ.OverlayField { 242 offset = 0 243 } 244 offset += fld.Size() 245 // Add dynamic alignment at the end and before the overlay part. 246 if i+1 == len(arg.Inner) || i+1 == typ.OverlayField { 247 if typ.AlignAttr != 0 && offset%typ.AlignAttr != 0 { 248 offset += typ.AlignAttr - offset%typ.AlignAttr 249 } 250 } 251 if size < offset { 252 size = offset 253 } 254 } 255 return size 256 case *ArrayType: 257 var size uint64 258 for _, elem := range arg.Inner { 259 size += elem.Size() 260 } 261 return size 262 default: 263 panic(fmt.Sprintf("bad group arg type %v", typ)) 264 } 265 } 266 267 func (arg *GroupArg) fixedInnerSize() bool { 268 switch typ := arg.Type().(type) { 269 case *StructType: 270 return true 271 case *ArrayType: 272 return typ.Kind == ArrayRangeLen && typ.RangeBegin == typ.RangeEnd 273 default: 274 panic(fmt.Sprintf("bad group arg type %v", typ)) 275 } 276 } 277 278 // Used for UnionType. 279 type UnionArg struct { 280 ArgCommon 281 Option Arg 282 Index int // Index of the selected option in the union type. 283 // Used for unions with conditional fields. 284 // We first create a dummy arg with transient=True and then 285 // patch them. 286 transient bool 287 } 288 289 func MakeUnionArg(t Type, dir Dir, opt Arg, index int) *UnionArg { 290 return &UnionArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Option: opt, Index: index} 291 } 292 293 func (arg *UnionArg) Size() uint64 { 294 if !arg.Type().Varlen() { 295 return arg.Type().Size() 296 } 297 return arg.Option.Size() 298 } 299 300 // Used for ResourceType. 301 // This is the only argument that can be used as syscall return value. 302 // Either holds constant value or reference another ResultArg. 303 type ResultArg struct { 304 ArgCommon 305 Res *ResultArg // reference to arg which we use 306 OpDiv uint64 // divide result (executed before OpAdd) 307 OpAdd uint64 // add to result 308 Val uint64 // value used if Res is nil 309 uses map[*ResultArg]bool // args that use this arg 310 } 311 312 func MakeResultArg(t Type, dir Dir, r *ResultArg, v uint64) *ResultArg { 313 arg := &ResultArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Res: r, Val: v} 314 if r == nil { 315 return arg 316 } 317 if r.uses == nil { 318 r.uses = make(map[*ResultArg]bool) 319 } 320 r.uses[arg] = true 321 return arg 322 } 323 324 func MakeReturnArg(t Type) *ResultArg { 325 if t == nil { 326 return nil 327 } 328 return &ResultArg{ArgCommon: ArgCommon{ref: t.ref(), dir: DirOut}} 329 } 330 331 func (arg *ResultArg) Size() uint64 { 332 return arg.Type().Size() 333 } 334 335 // Returns inner arg for pointer args. 336 func InnerArg(arg Arg) Arg { 337 if _, ok := arg.Type().(*PtrType); ok { 338 res := arg.(*PointerArg).Res 339 if res == nil { 340 return nil 341 } 342 return InnerArg(res) 343 } 344 return arg // Not a pointer. 345 } 346 347 func isDefault(arg Arg) bool { 348 return arg.Type().isDefaultArg(arg) 349 } 350 351 func (p *Prog) insertBefore(c *Call, calls []*Call) { 352 idx := 0 353 for ; idx < len(p.Calls); idx++ { 354 if p.Calls[idx] == c { 355 break 356 } 357 } 358 var newCalls []*Call 359 newCalls = append(newCalls, p.Calls[:idx]...) 360 newCalls = append(newCalls, calls...) 361 if idx < len(p.Calls) { 362 newCalls = append(newCalls, p.Calls[idx]) 363 newCalls = append(newCalls, p.Calls[idx+1:]...) 364 } 365 p.Calls = newCalls 366 } 367 368 // replaceArg replaces arg with arg1 in a program. 369 func replaceArg(arg, arg1 Arg) { 370 if arg == arg1 { 371 panic("replacing an argument with itself") 372 } 373 switch a := arg.(type) { 374 case *ConstArg: 375 *a = *arg1.(*ConstArg) 376 case *ResultArg: 377 replaceResultArg(a, arg1.(*ResultArg)) 378 case *PointerArg: 379 *a = *arg1.(*PointerArg) 380 case *UnionArg: 381 if a.Option != nil { 382 removeArg(a.Option) 383 } 384 *a = *arg1.(*UnionArg) 385 case *DataArg: 386 *a = *arg1.(*DataArg) 387 case *GroupArg: 388 _, isStruct := arg.Type().(*StructType) 389 a1 := arg1.(*GroupArg) 390 if isStruct && len(a.Inner) != len(a1.Inner) { 391 panic(fmt.Sprintf("replaceArg: group fields don't match: %v/%v", 392 len(a.Inner), len(a1.Inner))) 393 } 394 a.ArgCommon = a1.ArgCommon 395 // Replace min(|a|, |a1|) arguments. 396 for i := 0; i < len(a.Inner) && i < len(a1.Inner); i++ { 397 replaceArg(a.Inner[i], a1.Inner[i]) 398 } 399 // Remove extra arguments of a. 400 for len(a.Inner) > len(a1.Inner) { 401 i := len(a.Inner) - 1 402 removeArg(a.Inner[i]) 403 a.Inner[i] = nil 404 a.Inner = a.Inner[:i] 405 } 406 // Add extra arguments to a. 407 for i := len(a.Inner); i < len(a1.Inner); i++ { 408 a.Inner = append(a.Inner, a1.Inner[i]) 409 } 410 if debug && len(a.Inner) != len(a1.Inner) { 411 panic("replaceArg implementation bug") 412 } 413 default: 414 panic(fmt.Sprintf("replaceArg: bad arg kind %#v", arg)) 415 } 416 } 417 418 func replaceResultArg(arg, arg1 *ResultArg) { 419 // Remove link from `a.Res` to `arg`. 420 if arg.Res != nil { 421 delete(arg.Res.uses, arg) 422 } 423 // Copy all fields from `arg1` to `arg` except for the list of args that use `arg`. 424 uses := arg.uses 425 *arg = *arg1 426 arg.uses = uses 427 // Make the link in `arg.Res` (which is now `Res` of `arg1`) to point to `arg` instead of `arg1`. 428 if arg.Res != nil { 429 resUses := arg.Res.uses 430 delete(resUses, arg1) 431 resUses[arg] = true 432 } 433 } 434 435 // removeArg removes all references to/from arg0 from a program. 436 func removeArg(arg0 Arg) { 437 ForeachSubArg(arg0, func(arg Arg, ctx *ArgCtx) { 438 a, ok := arg.(*ResultArg) 439 if !ok { 440 return 441 } 442 if a.Res != nil { 443 uses := a.Res.uses 444 if !uses[a] { 445 panic("broken tree") 446 } 447 delete(uses, a) 448 } 449 for arg1 := range a.uses { 450 arg2 := arg1.Type().DefaultArg(arg1.Dir()).(*ResultArg) 451 replaceResultArg(arg1, arg2) 452 } 453 }) 454 } 455 456 // The public alias for the removeArg method. 457 func RemoveArg(arg Arg) { 458 removeArg(arg) 459 } 460 461 // removeCall removes call idx from p. 462 func (p *Prog) RemoveCall(idx int) { 463 c := p.Calls[idx] 464 for _, arg := range c.Args { 465 removeArg(arg) 466 } 467 if c.Ret != nil { 468 removeArg(c.Ret) 469 } 470 copy(p.Calls[idx:], p.Calls[idx+1:]) 471 p.Calls = p.Calls[:len(p.Calls)-1] 472 } 473 474 func (p *Prog) sanitizeFix() { 475 if err := p.sanitize(true); err != nil { 476 panic(err) 477 } 478 } 479 480 func (p *Prog) sanitize(fix bool) error { 481 for _, c := range p.Calls { 482 if err := p.Target.sanitize(c, fix); err != nil { 483 return err 484 } 485 } 486 return nil 487 } 488 489 // TODO: This method might be more generic - it can be applied to any struct. 490 func (props *CallProps) ForeachProp(f func(fieldName, key string, value reflect.Value)) { 491 valueObj := reflect.ValueOf(props).Elem() 492 typeObj := valueObj.Type() 493 for i := 0; i < valueObj.NumField(); i++ { 494 fieldValue := valueObj.Field(i) 495 fieldType := typeObj.Field(i) 496 f(fieldType.Name, fieldType.Tag.Get("key"), fieldValue) 497 } 498 }