github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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 "strings" 10 ) 11 12 type Prog struct { 13 Target *Target 14 Calls []*Call 15 Comments []string 16 17 // Was deserialized using Unsafe mode, so can do unsafe things. 18 isUnsafe bool 19 } 20 21 const ExtraCallName = ".extra" 22 23 func (p *Prog) CallName(call int) string { 24 if call >= len(p.Calls) || call < -1 { 25 panic(fmt.Sprintf("bad call index %v/%v", call, len(p.Calls))) 26 } 27 if call == -1 { 28 return ExtraCallName 29 } 30 return p.Calls[call].Meta.Name 31 } 32 33 // OnlyContains determines whether the program only consists of the syscalls from the first argument. 34 func (p *Prog) OnlyContains(syscalls map[*Syscall]bool) bool { 35 for _, c := range p.Calls { 36 if !syscalls[c.Meta] { 37 return false 38 } 39 } 40 return true 41 } 42 43 // FilterInplace only leaves the allowed system calls and deletes all remaining ones. 44 func (p *Prog) FilterInplace(allowed map[*Syscall]bool) { 45 for i := 0; i < len(p.Calls); { 46 c := p.Calls[i] 47 if !allowed[c.Meta] { 48 p.RemoveCall(i) 49 continue 50 } 51 i++ 52 } 53 } 54 55 // These properties are parsed and serialized according to the tag and the type 56 // of the corresponding fields. 57 // IMPORTANT: keep the exact values of "key" tag for existing props unchanged, 58 // otherwise the backwards compatibility would be broken. 59 type CallProps struct { 60 FailNth int `key:"fail_nth"` 61 Async bool `key:"async"` 62 Rerun int `key:"rerun"` 63 } 64 65 type Call struct { 66 Meta *Syscall 67 Args []Arg 68 Ret *ResultArg 69 Props CallProps 70 Comment string 71 } 72 73 func MakeCall(meta *Syscall, args []Arg) *Call { 74 return &Call{ 75 Meta: meta, 76 Args: args, 77 Ret: MakeReturnArg(meta.Ret), 78 } 79 } 80 81 type Arg interface { 82 Type() Type 83 Dir() Dir 84 Size() uint64 85 86 validate(ctx *validCtx, dir Dir) error 87 serialize(ctx *serializer) 88 } 89 90 type ArgCommon struct { 91 ref Ref 92 dir Dir 93 } 94 95 func (arg *ArgCommon) Type() Type { 96 if arg.ref == 0 { 97 panic("broken type ref") 98 } 99 return typeRefs.Load().([]Type)[arg.ref] 100 } 101 102 func (arg *ArgCommon) Dir() Dir { 103 return arg.dir 104 } 105 106 // Used for ConstType, IntType, FlagsType, LenType, ProcType and CsumType. 107 type ConstArg struct { 108 ArgCommon 109 Val uint64 110 } 111 112 func MakeConstArg(t Type, dir Dir, v uint64) *ConstArg { 113 return &ConstArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Val: v} 114 } 115 116 func (arg *ConstArg) Size() uint64 { 117 return arg.Type().Size() 118 } 119 120 // Value returns value and pid stride. 121 func (arg *ConstArg) Value() (uint64, uint64) { 122 switch typ := (*arg).Type().(type) { 123 case *IntType: 124 return arg.Val, 0 125 case *ConstType: 126 return arg.Val, 0 127 case *FlagsType: 128 return arg.Val, 0 129 case *LenType: 130 return arg.Val, 0 131 case *ResourceType: 132 return arg.Val, 0 133 case *CsumType: 134 // Checksums are computed dynamically in executor. 135 return 0, 0 136 case *ProcType: 137 if arg.Val == procDefaultValue { 138 return 0, 0 139 } 140 return typ.ValuesStart + arg.Val, typ.ValuesPerProc 141 default: 142 panic(fmt.Sprintf("unknown ConstArg type %#v", typ)) 143 } 144 } 145 146 // Used for PtrType and VmaType. 147 type PointerArg struct { 148 ArgCommon 149 Address uint64 150 VmaSize uint64 // size of the referenced region for vma args 151 Res Arg // pointee (nil for vma) 152 } 153 154 func MakePointerArg(t Type, dir Dir, addr uint64, data Arg) *PointerArg { 155 if data == nil { 156 panic("nil pointer data arg") 157 } 158 return &PointerArg{ 159 ArgCommon: ArgCommon{ref: t.ref(), dir: DirIn}, // pointers are always in 160 Address: addr, 161 Res: data, 162 } 163 } 164 165 func MakeVmaPointerArg(t Type, dir Dir, addr, size uint64) *PointerArg { 166 if addr%1024 != 0 { 167 panic("unaligned vma address") 168 } 169 return &PointerArg{ 170 ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, 171 Address: addr, 172 VmaSize: size, 173 } 174 } 175 176 func MakeSpecialPointerArg(t Type, dir Dir, index uint64) *PointerArg { 177 if index >= maxSpecialPointers { 178 panic("bad special pointer index") 179 } 180 if _, ok := t.(*PtrType); ok { 181 dir = DirIn // pointers are always in 182 } 183 return &PointerArg{ 184 ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, 185 Address: -index, 186 } 187 } 188 189 func (arg *PointerArg) Size() uint64 { 190 return arg.Type().Size() 191 } 192 193 func (arg *PointerArg) IsSpecial() bool { 194 return arg.VmaSize == 0 && arg.Res == nil && -arg.Address < maxSpecialPointers 195 } 196 197 func (target *Target) PhysicalAddr(arg *PointerArg) uint64 { 198 if arg.IsSpecial() { 199 return target.SpecialPointers[-arg.Address] 200 } 201 return target.DataOffset + arg.Address 202 } 203 204 // Used for BufferType. 205 type DataArg struct { 206 ArgCommon 207 data []byte // for in/inout args 208 size uint64 // for out Args 209 } 210 211 func MakeDataArg(t Type, dir Dir, data []byte) *DataArg { 212 if dir == DirOut { 213 panic("non-empty output data arg") 214 } 215 return &DataArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, data: append([]byte{}, data...)} 216 } 217 218 func MakeOutDataArg(t Type, dir Dir, size uint64) *DataArg { 219 if dir != DirOut { 220 panic("empty input data arg") 221 } 222 return &DataArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, size: size} 223 } 224 225 func (arg *DataArg) Size() uint64 { 226 if len(arg.data) != 0 { 227 return uint64(len(arg.data)) 228 } 229 return arg.size 230 } 231 232 func (arg *DataArg) Data() []byte { 233 if arg.Dir() == DirOut { 234 panic("getting data of output data arg") 235 } 236 return arg.data 237 } 238 239 func (arg *DataArg) SetData(data []byte) { 240 if arg.Dir() == DirOut { 241 panic("setting data of output data arg") 242 } 243 arg.data = append([]byte{}, data...) 244 } 245 246 // Used for StructType and ArrayType. 247 // Logical group of args (struct or array). 248 type GroupArg struct { 249 ArgCommon 250 Inner []Arg 251 } 252 253 func MakeGroupArg(t Type, dir Dir, inner []Arg) *GroupArg { 254 return &GroupArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Inner: inner} 255 } 256 257 func (arg *GroupArg) Size() uint64 { 258 typ0 := arg.Type() 259 if !typ0.Varlen() { 260 return typ0.Size() 261 } 262 switch typ := typ0.(type) { 263 case *StructType: 264 var size, offset uint64 265 for i, fld := range arg.Inner { 266 if i == typ.OverlayField { 267 offset = 0 268 } 269 offset += fld.Size() 270 // Add dynamic alignment at the end and before the overlay part. 271 if i+1 == len(arg.Inner) || i+1 == typ.OverlayField { 272 if typ.AlignAttr != 0 && offset%typ.AlignAttr != 0 { 273 offset += typ.AlignAttr - offset%typ.AlignAttr 274 } 275 } 276 size = max(size, offset) 277 } 278 return size 279 case *ArrayType: 280 var size uint64 281 for _, elem := range arg.Inner { 282 size += elem.Size() 283 } 284 return size 285 default: 286 panic(fmt.Sprintf("bad group arg type %v", typ)) 287 } 288 } 289 290 func (arg *GroupArg) fixedInnerSize() bool { 291 switch typ := arg.Type().(type) { 292 case *StructType: 293 return true 294 case *ArrayType: 295 return typ.Kind == ArrayRangeLen && typ.RangeBegin == typ.RangeEnd 296 default: 297 panic(fmt.Sprintf("bad group arg type %v", typ)) 298 } 299 } 300 301 // Used for UnionType. 302 type UnionArg struct { 303 ArgCommon 304 Option Arg 305 Index int // Index of the selected option in the union type. 306 // Used for unions with conditional fields. 307 // We first create a dummy arg with transient=True and then 308 // patch them. 309 transient bool 310 } 311 312 func MakeUnionArg(t Type, dir Dir, opt Arg, index int) *UnionArg { 313 return &UnionArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Option: opt, Index: index} 314 } 315 316 func (arg *UnionArg) Size() uint64 { 317 if !arg.Type().Varlen() { 318 return arg.Type().Size() 319 } 320 return arg.Option.Size() 321 } 322 323 // Used for ResourceType. 324 // This is the only argument that can be used as syscall return value. 325 // Either holds constant value or reference another ResultArg. 326 type ResultArg struct { 327 ArgCommon 328 Res *ResultArg // reference to arg which we use 329 OpDiv uint64 // divide result (executed before OpAdd) 330 OpAdd uint64 // add to result 331 Val uint64 // value used if Res is nil 332 uses map[*ResultArg]bool // args that use this arg 333 } 334 335 func MakeResultArg(t Type, dir Dir, r *ResultArg, v uint64) *ResultArg { 336 arg := &ResultArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Res: r, Val: v} 337 if r == nil { 338 return arg 339 } 340 if r.uses == nil { 341 r.uses = make(map[*ResultArg]bool) 342 } 343 r.uses[arg] = true 344 return arg 345 } 346 347 func MakeReturnArg(t Type) *ResultArg { 348 if t == nil { 349 return nil 350 } 351 return &ResultArg{ArgCommon: ArgCommon{ref: t.ref(), dir: DirOut}} 352 } 353 354 func (arg *ResultArg) Size() uint64 { 355 return arg.Type().Size() 356 } 357 358 // Returns inner arg for pointer args. 359 func InnerArg(arg Arg) Arg { 360 if _, ok := arg.Type().(*PtrType); ok { 361 res := arg.(*PointerArg).Res 362 if res == nil { 363 return nil 364 } 365 return InnerArg(res) 366 } 367 return arg // Not a pointer. 368 } 369 370 func isDefault(arg Arg) bool { 371 return arg.Type().isDefaultArg(arg) 372 } 373 374 func (p *Prog) insertBefore(c *Call, calls []*Call) { 375 idx := 0 376 for ; idx < len(p.Calls); idx++ { 377 if p.Calls[idx] == c { 378 break 379 } 380 } 381 var newCalls []*Call 382 newCalls = append(newCalls, p.Calls[:idx]...) 383 newCalls = append(newCalls, calls...) 384 if idx < len(p.Calls) { 385 newCalls = append(newCalls, p.Calls[idx]) 386 newCalls = append(newCalls, p.Calls[idx+1:]...) 387 } 388 p.Calls = newCalls 389 } 390 391 // replaceArg replaces arg with arg1 in a program. 392 func replaceArg(arg, arg1 Arg) { 393 if arg == arg1 { 394 panic("replacing an argument with itself") 395 } 396 switch a := arg.(type) { 397 case *ConstArg: 398 *a = *arg1.(*ConstArg) 399 case *ResultArg: 400 replaceResultArg(a, arg1.(*ResultArg)) 401 case *PointerArg: 402 *a = *arg1.(*PointerArg) 403 case *UnionArg: 404 if a.Option != nil { 405 removeArg(a.Option) 406 } 407 *a = *arg1.(*UnionArg) 408 case *DataArg: 409 *a = *arg1.(*DataArg) 410 case *GroupArg: 411 _, isStruct := arg.Type().(*StructType) 412 a1 := arg1.(*GroupArg) 413 if isStruct && len(a.Inner) != len(a1.Inner) { 414 panic(fmt.Sprintf("replaceArg: group fields don't match: %v/%v", 415 len(a.Inner), len(a1.Inner))) 416 } 417 a.ArgCommon = a1.ArgCommon 418 // Replace min(|a|, |a1|) arguments. 419 for i := 0; i < len(a.Inner) && i < len(a1.Inner); i++ { 420 replaceArg(a.Inner[i], a1.Inner[i]) 421 } 422 // Remove extra arguments of a. 423 for len(a.Inner) > len(a1.Inner) { 424 i := len(a.Inner) - 1 425 removeArg(a.Inner[i]) 426 a.Inner[i] = nil 427 a.Inner = a.Inner[:i] 428 } 429 // Add extra arguments to a. 430 for i := len(a.Inner); i < len(a1.Inner); i++ { 431 a.Inner = append(a.Inner, a1.Inner[i]) 432 } 433 if debug && len(a.Inner) != len(a1.Inner) { 434 panic("replaceArg implementation bug") 435 } 436 default: 437 panic(fmt.Sprintf("replaceArg: bad arg kind %#v", arg)) 438 } 439 } 440 441 func replaceResultArg(arg, arg1 *ResultArg) { 442 // Remove link from `a.Res` to `arg`. 443 if arg.Res != nil { 444 delete(arg.Res.uses, arg) 445 } 446 // Copy all fields from `arg1` to `arg` except for the list of args that use `arg`. 447 uses := arg.uses 448 *arg = *arg1 449 arg.uses = uses 450 // Make the link in `arg.Res` (which is now `Res` of `arg1`) to point to `arg` instead of `arg1`. 451 if arg.Res != nil { 452 resUses := arg.Res.uses 453 delete(resUses, arg1) 454 resUses[arg] = true 455 } 456 } 457 458 // removeArg removes all references to/from arg0 from a program. 459 func removeArg(arg0 Arg) { 460 ForeachSubArg(arg0, func(arg Arg, ctx *ArgCtx) { 461 a, ok := arg.(*ResultArg) 462 if !ok { 463 return 464 } 465 if a.Res != nil { 466 uses := a.Res.uses 467 if !uses[a] { 468 panic("broken tree") 469 } 470 delete(uses, a) 471 } 472 for arg1 := range a.uses { 473 arg2 := arg1.Type().DefaultArg(arg1.Dir()).(*ResultArg) 474 replaceResultArg(arg1, arg2) 475 } 476 }) 477 } 478 479 // RemoveCall removes call idx from p. 480 func (p *Prog) RemoveCall(idx int) { 481 c := p.Calls[idx] 482 for _, arg := range c.Args { 483 removeArg(arg) 484 } 485 if c.Ret != nil { 486 removeArg(c.Ret) 487 } 488 copy(p.Calls[idx:], p.Calls[idx+1:]) 489 p.Calls = p.Calls[:len(p.Calls)-1] 490 } 491 492 func (p *Prog) sanitizeFix() { 493 if err := p.sanitize(true); err != nil { 494 panic(err) 495 } 496 } 497 498 // FormatArg returns a string slice representation of an argument with one 499 // entry per line in the output. The formatting roughly corresponds to syzlang 500 // descriptions and is intended to be human readable. 501 func FormatArg(arg Arg, name string) []string { 502 const indent string = " " // Two spaces. 503 makeIndent := func(level int) string { 504 return strings.Repeat(indent, level) 505 } 506 507 // Depth-first search starting at initial argument, incrementing the indent 508 // level as we go deeper. 509 var visit func(Arg, string, int) []string 510 visit = func(arg Arg, name string, depth int) []string { 511 var lines []string 512 513 var lineBuilder strings.Builder 514 lineBuilder.WriteString(makeIndent(depth)) 515 516 if name != "" { 517 fmt.Fprintf(&lineBuilder, "%s: ", name) 518 } 519 520 switch a := arg.(type) { 521 case *GroupArg: 522 fmt.Fprintf(&lineBuilder, "%s {", a.Type().String()) 523 lines = append(lines, lineBuilder.String()) 524 525 s, isStruct := a.ArgCommon.Type().(*StructType) 526 for i, inner := range a.Inner { 527 // For GroupArgs, only those of type StructType have named 528 // children. 529 childName := "" 530 if isStruct { 531 childName = s.Fields[i].Name 532 } 533 lines = append(lines, visit(inner, childName, depth+1)...) 534 } 535 lines = append(lines, makeIndent(depth)+"}") 536 case *ConstArg: 537 fmt.Fprintf(&lineBuilder, "%s = 0x%x (%d bytes)", a.Type().Name(), a.Val, a.Size()) 538 lines = append(lines, lineBuilder.String()) 539 case *DataArg: 540 tpe, ok := a.Type().(*BufferType) 541 if !ok { 542 panic("data args should be a buffer type") 543 } 544 545 fmt.Fprintf(&lineBuilder, "%s: ", a.Type().String()) 546 547 // Result buffer - nothing to display. 548 if a.Dir() == DirOut { 549 fmt.Fprint(&lineBuilder, "(DirOut)") 550 } else { 551 // Compressed buffers (e.g., fs images) tend to be very large 552 // and it doesn't make much sense to output their contents. 553 if tpe.Kind == BufferCompressed { 554 fmt.Fprintf(&lineBuilder, "(compressed buffer with length 0x%x)", len(a.Data())) 555 } else { 556 fmt.Fprintf(&lineBuilder, "{% x} (length 0x%x)", a.Data(), len(a.Data())) 557 } 558 } 559 lines = append(lines, lineBuilder.String()) 560 case *PointerArg: 561 if a.Res != nil { 562 fmt.Fprintf(&lineBuilder, "%s {", a.Type().String()) 563 lines = append(lines, lineBuilder.String()) 564 lines = append(lines, visit(a.Res, "", depth+1)...) 565 lines = append(lines, makeIndent(depth)+"}") 566 } else { 567 if a.VmaSize == 0 { 568 lineBuilder.WriteString("nil") 569 } else { 570 fmt.Fprintf(&lineBuilder, "VMA[0x%x]", a.VmaSize) 571 } 572 lines = append(lines, lineBuilder.String()) 573 } 574 case *UnionArg: 575 union, ok := a.ArgCommon.Type().(*UnionType) 576 if !ok { 577 panic("a UnionArg should have an ArgCommon of type UnionType") 578 } 579 fmt.Fprintf(&lineBuilder, "union %s {", a.Type().Name()) 580 lines = append(lines, lineBuilder.String()) 581 if a.Option != nil { 582 lines = append(lines, visit(a.Option, union.Fields[a.Index].Name, depth+1)...) 583 } 584 lines = append(lines, makeIndent(depth)+"}") 585 case *ResultArg: 586 fmt.Fprintf(&lineBuilder, "%s (resource)", a.ArgCommon.Type().String()) 587 lines = append(lines, lineBuilder.String()) 588 default: 589 // We shouldn't hit this because the switch statements cover every 590 // prog.Arg implementation. 591 panic("Unsupported argument type.") 592 } 593 return lines 594 } 595 596 return visit(arg, name, 0) 597 } 598 599 func (p *Prog) sanitize(fix bool) error { 600 for _, c := range p.Calls { 601 if err := p.Target.sanitize(c, fix); err != nil { 602 return err 603 } 604 } 605 return nil 606 } 607 608 // TODO: This method might be more generic - it can be applied to any struct. 609 func (props *CallProps) ForeachProp(f func(fieldName, key string, value reflect.Value)) { 610 valueObj := reflect.ValueOf(props).Elem() 611 typeObj := valueObj.Type() 612 for i := 0; i < valueObj.NumField(); i++ { 613 fieldValue := valueObj.Field(i) 614 fieldType := typeObj.Field(i) 615 f(fieldType.Name, fieldType.Tag.Get("key"), fieldValue) 616 } 617 }