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