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 }