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  }