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 }