github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/any.go (about)

     1  // Copyright 2018 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  )
     9  
    10  type anyTypes struct {
    11  	union  *UnionType
    12  	array  *ArrayType
    13  	blob   *BufferType
    14  	ptrPtr *PtrType
    15  	ptr64  *PtrType
    16  	res8   *ResourceType
    17  	res16  *ResourceType
    18  	res32  *ResourceType
    19  	res64  *ResourceType
    20  	resdec *ResourceType
    21  	reshex *ResourceType
    22  	resoct *ResourceType
    23  }
    24  
    25  func (target *Target) initAnyTypes() {
    26  	var anyPtrs *UnionType
    27  	for _, typ := range target.types {
    28  		if typ.Name() == "ANYPTRS" {
    29  			anyPtrs = typ.(*UnionType)
    30  			break
    31  		}
    32  	}
    33  	if anyPtrs == nil {
    34  		panic("no builtin ANYPTRS type")
    35  	}
    36  	// These types are generated by builtin descriptions in pkg/compiler/types.go.
    37  	target.any.ptrPtr = anyPtrs.Fields[0].Type.(*PtrType)
    38  	target.any.ptr64 = anyPtrs.Fields[1].Type.(*PtrType)
    39  	target.any.array = target.any.ptrPtr.Elem.(*ArrayType)
    40  	target.any.union = target.any.array.Elem.(*UnionType)
    41  	target.any.blob = target.any.union.Fields[0].Type.(*BufferType)
    42  	target.any.res8 = target.any.union.Fields[1].Type.(*ResourceType)
    43  	target.any.res16 = target.any.union.Fields[2].Type.(*ResourceType)
    44  	target.any.res32 = target.any.union.Fields[3].Type.(*ResourceType)
    45  	target.any.res64 = target.any.union.Fields[4].Type.(*ResourceType)
    46  	target.any.resdec = target.any.union.Fields[5].Type.(*ResourceType)
    47  	target.any.reshex = target.any.union.Fields[6].Type.(*ResourceType)
    48  	target.any.resoct = target.any.union.Fields[7].Type.(*ResourceType)
    49  }
    50  
    51  func (target *Target) getAnyPtrType(size uint64) *PtrType {
    52  	if size == target.PtrSize {
    53  		return target.any.ptrPtr
    54  	} else if size == 8 {
    55  		return target.any.ptr64
    56  	}
    57  	panic(fmt.Sprintf("bad pointer size %v", size))
    58  }
    59  
    60  func (target *Target) isAnyPtr(typ Type) bool {
    61  	ptr, ok := typ.(*PtrType)
    62  	return ok && ptr.Elem == target.any.array
    63  }
    64  
    65  type complexPtr struct {
    66  	arg  *PointerArg
    67  	call *Call
    68  }
    69  
    70  func (p *Prog) complexPtrs() (res []complexPtr) {
    71  	for _, c := range p.Calls {
    72  		ForeachArg(c, func(arg Arg, ctx *ArgCtx) {
    73  			if ptrArg, ok := arg.(*PointerArg); ok && p.Target.isComplexPtr(ptrArg) {
    74  				res = append(res, complexPtr{ptrArg, c})
    75  				ctx.Stop = true
    76  			}
    77  		})
    78  	}
    79  	return
    80  }
    81  
    82  func (target *Target) isComplexPtr(arg *PointerArg) bool {
    83  	if arg.Res == nil || !arg.Type().(*PtrType).SquashableElem {
    84  		return false
    85  	}
    86  	if target.isAnyPtr(arg.Type()) {
    87  		return true
    88  	}
    89  	complex := false
    90  	ForeachSubArg(arg.Res, func(a1 Arg, ctx *ArgCtx) {
    91  		switch typ := a1.Type().(type) {
    92  		case *StructType:
    93  			if typ.Varlen() {
    94  				complex = true
    95  				ctx.Stop = true
    96  			}
    97  		case *UnionType:
    98  			if typ.Varlen() && len(typ.Fields) > 5 {
    99  				complex = true
   100  				ctx.Stop = true
   101  			}
   102  		}
   103  	})
   104  	return complex
   105  }
   106  
   107  func (target *Target) isAnyRes(name string) bool {
   108  	return name == target.any.res8.TypeName ||
   109  		name == target.any.res16.TypeName ||
   110  		name == target.any.res32.TypeName ||
   111  		name == target.any.res64.TypeName ||
   112  		name == target.any.resdec.TypeName ||
   113  		name == target.any.reshex.TypeName ||
   114  		name == target.any.resoct.TypeName
   115  }
   116  
   117  func (target *Target) CallContainsAny(c *Call) (res bool) {
   118  	ForeachArg(c, func(arg Arg, ctx *ArgCtx) {
   119  		if target.isAnyPtr(arg.Type()) || res {
   120  			res = true
   121  			ctx.Stop = true
   122  		}
   123  	})
   124  	return
   125  }
   126  
   127  func (target *Target) ArgContainsAny(arg0 Arg) (res bool) {
   128  	ForeachSubArg(arg0, func(arg Arg, ctx *ArgCtx) {
   129  		if target.isAnyPtr(arg.Type()) || res {
   130  			res = true
   131  			ctx.Stop = true
   132  		}
   133  	})
   134  	return
   135  }
   136  
   137  func (target *Target) squashPtr(arg *PointerArg) {
   138  	if arg.Res == nil || arg.VmaSize != 0 {
   139  		panic("bad ptr arg")
   140  	}
   141  	res0 := arg.Res
   142  	size0 := res0.Size()
   143  	var elems []Arg
   144  	target.squashPtrImpl(arg.Res, &elems)
   145  	newType := target.getAnyPtrType(arg.Type().Size())
   146  	arg.ref = newType.ref()
   147  	arg.Res = MakeGroupArg(newType.Elem, DirIn, elems)
   148  	if size := arg.Res.Size(); size != size0 {
   149  		panic(fmt.Sprintf("squash changed size %v->%v for %v", size0, size, res0.Type()))
   150  	}
   151  }
   152  
   153  func (target *Target) squashPtrImpl(a Arg, elems *[]Arg) {
   154  	if a.Type().BitfieldLength() != 0 {
   155  		panic("bitfield in squash")
   156  	}
   157  	var pad uint64
   158  	switch arg := a.(type) {
   159  	case *ConstArg:
   160  		target.squashConst(arg, elems)
   161  	case *ResultArg:
   162  		target.squashResult(arg, elems)
   163  	case *UnionArg:
   164  		if !arg.Type().Varlen() {
   165  			pad = arg.Size() - arg.Option.Size()
   166  		}
   167  		target.squashPtrImpl(arg.Option, elems)
   168  	case *DataArg:
   169  		if arg.Dir() == DirOut {
   170  			pad = arg.Size()
   171  		} else {
   172  			elem := target.ensureDataElem(elems)
   173  			elem.data = append(elem.Data(), arg.Data()...)
   174  		}
   175  	case *GroupArg:
   176  		target.squashGroup(arg, elems)
   177  	default:
   178  		panic(fmt.Sprintf("bad arg kind %v (%#v) %v", a, a, a.Type()))
   179  	}
   180  	if pad != 0 {
   181  		elem := target.ensureDataElem(elems)
   182  		elem.data = append(elem.Data(), make([]byte, pad)...)
   183  	}
   184  }
   185  
   186  func (target *Target) squashConst(arg *ConstArg, elems *[]Arg) {
   187  	if IsPad(arg.Type()) {
   188  		elem := target.ensureDataElem(elems)
   189  		elem.data = append(elem.Data(), make([]byte, arg.Size())...)
   190  		return
   191  	}
   192  	v, bf := target.squashedValue(arg)
   193  	var data []byte
   194  	switch bf {
   195  	case FormatNative:
   196  		for i := uint64(0); i < arg.Size(); i++ {
   197  			data = append(data, byte(v))
   198  			v >>= 8
   199  		}
   200  	case FormatStrDec:
   201  		data = []byte(fmt.Sprintf("%020v", v))
   202  	case FormatStrHex:
   203  		data = []byte(fmt.Sprintf("0x%016x", v))
   204  	case FormatStrOct:
   205  		data = []byte(fmt.Sprintf("%023o", v))
   206  	default:
   207  		panic(fmt.Sprintf("unknown binary format: %v", bf))
   208  	}
   209  	if uint64(len(data)) != arg.Size() {
   210  		panic("squashed value of wrong size")
   211  	}
   212  	elem := target.ensureDataElem(elems)
   213  	elem.data = append(elem.Data(), data...)
   214  }
   215  
   216  func (target *Target) squashResult(arg *ResultArg, elems *[]Arg) {
   217  	var typ *ResourceType
   218  	index := -1
   219  	switch arg.Type().Format() {
   220  	case FormatNative, FormatBigEndian:
   221  		switch arg.Size() {
   222  		case 1:
   223  			typ, index = target.any.res8, 1
   224  		case 2:
   225  			typ, index = target.any.res16, 2
   226  		case 4:
   227  			typ, index = target.any.res32, 3
   228  		case 8:
   229  			typ, index = target.any.res64, 4
   230  		default:
   231  			panic(fmt.Sprintf("bad size %v", arg.Size()))
   232  		}
   233  	case FormatStrDec:
   234  		typ, index = target.any.resdec, 5
   235  	case FormatStrHex:
   236  		typ, index = target.any.reshex, 6
   237  	case FormatStrOct:
   238  		typ, index = target.any.resoct, 7
   239  	default:
   240  		panic("bad")
   241  	}
   242  	arg.ref = typ.ref()
   243  	*elems = append(*elems, MakeUnionArg(target.any.union, DirIn, arg, index))
   244  }
   245  
   246  func (target *Target) squashGroup(arg *GroupArg, elems *[]Arg) {
   247  	if typ, ok := arg.Type().(*StructType); ok && typ.OverlayField != 0 {
   248  		panic("squashing out_overlay")
   249  	}
   250  	var bitfield, fieldsSize uint64
   251  	for _, fld := range arg.Inner {
   252  		fieldsSize += fld.Size()
   253  		// Squash bitfields separately.
   254  		if fld.Type().IsBitfield() {
   255  			bfLen := fld.Type().BitfieldLength()
   256  			bfOff := fld.Type().BitfieldOffset()
   257  			// Note: we can have a ResultArg here as well,
   258  			// but it is unsupported at the moment.
   259  			v, bf := target.squashedValue(fld.(*ConstArg))
   260  			if bf != FormatNative {
   261  				panic(fmt.Sprintf("bitfield has bad format %v", bf))
   262  			}
   263  			bitfield |= (v & ((1 << bfLen) - 1)) << bfOff
   264  			if fld.Size() != 0 {
   265  				elem := target.ensureDataElem(elems)
   266  				for i := uint64(0); i < fld.Size(); i++ {
   267  					elem.data = append(elem.Data(), byte(bitfield))
   268  					bitfield >>= 8
   269  				}
   270  				bitfield = 0
   271  			}
   272  			continue
   273  		}
   274  		target.squashPtrImpl(fld, elems)
   275  	}
   276  	// Add padding either due to dynamic alignment or overlay fields.
   277  	if pad := arg.Size() - fieldsSize; pad != 0 {
   278  		elem := target.ensureDataElem(elems)
   279  		elem.data = append(elem.Data(), make([]byte, pad)...)
   280  	}
   281  }
   282  
   283  func (target *Target) squashedValue(arg *ConstArg) (uint64, BinaryFormat) {
   284  	typ := arg.Type()
   285  	bf := typ.Format()
   286  	if _, ok := typ.(*CsumType); ok {
   287  		// We can't compute value for the checksum here,
   288  		// but at least leave something recognizable by hints code.
   289  		// TODO: hints code won't recognize this, because it won't find
   290  		// the const in any arg. We either need to put this const as
   291  		// actual csum arg value, or special case it in hints.
   292  		return 0xabcdef1234567890, FormatNative
   293  	}
   294  	// Note: we need a constant value, but it depends on pid for proc.
   295  	v, _ := arg.Value()
   296  	if bf == FormatBigEndian {
   297  		bf = FormatNative
   298  		switch typ.UnitSize() {
   299  		case 2:
   300  			v = uint64(swap16(uint16(v)))
   301  		case 4:
   302  			v = uint64(swap32(uint32(v)))
   303  		case 8:
   304  			v = swap64(v)
   305  		default:
   306  			panic(fmt.Sprintf("bad const size %v", arg.Size()))
   307  		}
   308  	}
   309  	return v, bf
   310  }
   311  
   312  func (target *Target) ensureDataElem(elems *[]Arg) *DataArg {
   313  	if len(*elems) == 0 {
   314  		res := MakeDataArg(target.any.blob, DirIn, nil)
   315  		*elems = append(*elems, MakeUnionArg(target.any.union, DirIn, res, 0))
   316  		return res
   317  	}
   318  	res, ok := (*elems)[len(*elems)-1].(*UnionArg).Option.(*DataArg)
   319  	if !ok {
   320  		res = MakeDataArg(target.any.blob, DirIn, nil)
   321  		*elems = append(*elems, MakeUnionArg(target.any.union, DirIn, res, 0))
   322  	}
   323  	return res
   324  }