github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/decodeexec.go (about) 1 // Copyright 2017 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 "encoding/binary" 8 "fmt" 9 "reflect" 10 "strings" 11 ) 12 13 type ExecProg struct { 14 Calls []ExecCall 15 Vars []uint64 16 } 17 18 type ExecCall struct { 19 Meta *Syscall 20 Props CallProps 21 Index uint64 22 Args []ExecArg 23 Copyin []ExecCopyin 24 Copyout []ExecCopyout 25 } 26 27 type ExecCopyin struct { 28 Addr uint64 29 Arg ExecArg 30 } 31 32 type ExecCopyout struct { 33 Index uint64 34 Addr uint64 35 Size uint64 36 } 37 38 type ExecArg interface{} // one of ExecArg* 39 40 type ExecArgConst struct { 41 Size uint64 42 Format BinaryFormat 43 Value uint64 44 BitfieldOffset uint64 45 BitfieldLength uint64 46 PidStride uint64 47 } 48 49 type ExecArgResult struct { 50 Size uint64 51 Format BinaryFormat 52 Index uint64 53 DivOp uint64 54 AddOp uint64 55 Default uint64 56 } 57 58 type ExecArgData struct { 59 Data []byte 60 Readable bool 61 } 62 63 type ExecArgCsum struct { 64 Size uint64 65 Kind uint64 66 Chunks []ExecCsumChunk 67 } 68 69 type ExecCsumChunk struct { 70 Kind uint64 71 Value uint64 72 Size uint64 73 } 74 75 func ExecCallCount(exec []byte) (int, error) { 76 v, n := binary.Varint(exec) 77 if n <= 0 { 78 return 0, fmt.Errorf("not enough data in the buffer") 79 } 80 if v > MaxCalls { 81 return 0, fmt.Errorf("too many calls (%v)", v) 82 } 83 return int(v), nil 84 } 85 86 func (target *Target) DeserializeExec(exec []byte, stats map[string]int) (ExecProg, error) { 87 dec := &execDecoder{target: target, data: exec, stats: stats} 88 dec.parse() 89 if dec.err != nil { 90 return ExecProg{}, dec.err 91 } 92 if uint64(len(dec.vars)) != dec.numVars { 93 return ExecProg{}, fmt.Errorf("mismatching number of vars: %v/%v", 94 len(dec.vars), dec.numVars) 95 } 96 p := ExecProg{ 97 Calls: dec.calls, 98 Vars: dec.vars, 99 } 100 return p, nil 101 } 102 103 type execDecoder struct { 104 target *Target 105 data []byte 106 err error 107 numVars uint64 108 vars []uint64 109 call ExecCall 110 calls []ExecCall 111 stats map[string]int 112 } 113 114 func (dec *execDecoder) parse() { 115 ncalls := dec.read("header") 116 for dec.err == nil { 117 switch instr := dec.read("instr/opcode"); instr { 118 case execInstrCopyin: 119 dec.commitCall() 120 dec.call.Copyin = append(dec.call.Copyin, ExecCopyin{ 121 Addr: dec.read("instr/copyin") + dec.target.DataOffset, 122 Arg: dec.readArg(), 123 }) 124 case execInstrCopyout: 125 dec.call.Copyout = append(dec.call.Copyout, ExecCopyout{ 126 Index: dec.read("instr/copyout/index"), 127 Addr: dec.read("instr/copyout/addr") + dec.target.DataOffset, 128 Size: dec.read("instr/copyout/size"), 129 }) 130 case execInstrEOF: 131 dec.commitCall() 132 if ncalls != uint64(len(dec.calls)) { 133 dec.err = fmt.Errorf("bad number of calls: %v/%v", ncalls, len(dec.calls)) 134 } 135 return 136 case execInstrSetProps: 137 dec.commitCall() 138 dec.readCallProps(&dec.call.Props) 139 default: 140 dec.commitCall() 141 if instr >= uint64(len(dec.target.Syscalls)) { 142 dec.setErr(fmt.Errorf("bad syscall %v", instr)) 143 return 144 } 145 dec.call.Meta = dec.target.Syscalls[instr] 146 dec.call.Index = dec.read("instr/index") 147 for i := dec.read("instr/nargs"); i > 0; i-- { 148 switch arg := dec.readArg(); arg.(type) { 149 case ExecArgConst, ExecArgResult: 150 dec.call.Args = append(dec.call.Args, arg) 151 default: 152 dec.setErr(fmt.Errorf("bad call arg %+v", arg)) 153 return 154 } 155 } 156 } 157 } 158 } 159 160 func (dec *execDecoder) readCallProps(props *CallProps) { 161 props.ForeachProp(func(_, _ string, value reflect.Value) { 162 arg := dec.read("call prop") 163 switch kind := value.Kind(); kind { 164 case reflect.Int: 165 value.SetInt(int64(arg)) 166 case reflect.Bool: 167 if arg == 1 { 168 value.SetBool(true) 169 } 170 default: 171 panic("Unsupported (yet) kind: " + kind.String()) 172 } 173 }) 174 } 175 176 func (dec *execDecoder) readArg() ExecArg { 177 switch typ := dec.read("arg/type"); typ { 178 case execArgConst: 179 meta := dec.read("arg/const/meta") 180 return ExecArgConst{ 181 Value: dec.read("arg/const/value"), 182 Size: meta & 0xff, 183 Format: BinaryFormat((meta >> 8) & 0xff), 184 BitfieldOffset: (meta >> 16) & 0xff, 185 BitfieldLength: (meta >> 24) & 0xff, 186 PidStride: meta >> 32, 187 } 188 case execArgAddr32: 189 fallthrough 190 case execArgAddr64: 191 size := 4 192 if typ == execArgAddr64 { 193 size = 8 194 } 195 return ExecArgConst{ 196 Value: dec.read("arg/addr") + dec.target.DataOffset, 197 Size: uint64(size), 198 } 199 case execArgResult: 200 meta := dec.read("arg/result/meta") 201 arg := ExecArgResult{ 202 Size: meta & 0xff, 203 Format: BinaryFormat((meta >> 8) & 0xff), 204 Index: dec.read("arg/result/index"), 205 DivOp: dec.read("arg/result/divop"), 206 AddOp: dec.read("arg/result/addop"), 207 Default: dec.read("arg/result/default"), 208 } 209 for uint64(len(dec.vars)) <= arg.Index { 210 dec.vars = append(dec.vars, 0) 211 } 212 dec.vars[arg.Index] = arg.Default 213 return arg 214 case execArgData: 215 flags := dec.read("arg/data/size") 216 size := flags & ^execArgDataReadable 217 dec.addStat("arg/data/blob", int(size)) 218 readable := flags&execArgDataReadable != 0 219 return ExecArgData{ 220 Data: dec.readBlob(size), 221 Readable: readable, 222 } 223 case execArgCsum: 224 size := dec.read("arg/csum/size") 225 switch kind := dec.read("arg/csum/kind"); kind { 226 case ExecArgCsumInet: 227 chunks := make([]ExecCsumChunk, dec.read("arg/csum/chunks")) 228 for i := range chunks { 229 kind := dec.read("arg/csum/chunk/kind") 230 addr := dec.read("arg/csum/chunk/addr") 231 size := dec.read("arg/csum/chunk/size") 232 if kind == ExecArgCsumChunkData { 233 addr += dec.target.DataOffset 234 } 235 chunks[i] = ExecCsumChunk{ 236 Kind: kind, 237 Value: addr, 238 Size: size, 239 } 240 } 241 return ExecArgCsum{ 242 Size: size, 243 Kind: kind, 244 Chunks: chunks, 245 } 246 default: 247 dec.setErr(fmt.Errorf("unknown csum kind %v", kind)) 248 return nil 249 } 250 default: 251 dec.setErr(fmt.Errorf("bad argument type %v", typ)) 252 return nil 253 } 254 } 255 256 func (dec *execDecoder) read(stat string) uint64 { 257 if dec.err != nil { 258 return 0 259 } 260 v, n := binary.Varint(dec.data) 261 if n <= 0 { 262 dec.setErr(fmt.Errorf("exec program overflow")) 263 return 0 264 } 265 dec.addStat(stat, n) 266 dec.data = dec.data[n:] 267 return uint64(v) 268 } 269 270 func (dec *execDecoder) readBlob(size uint64) []byte { 271 if uint64(len(dec.data)) < size { 272 dec.setErr(fmt.Errorf("exec program overflow")) 273 } 274 if dec.err != nil { 275 return nil 276 } 277 data := dec.data[:size] 278 dec.data = dec.data[size:] 279 return data 280 } 281 282 func (dec *execDecoder) setErr(err error) { 283 if dec.err == nil { 284 dec.err = err 285 } 286 } 287 288 func (dec *execDecoder) commitCall() { 289 if dec.call.Meta == nil { 290 return 291 } 292 if dec.call.Index != ExecNoCopyout && dec.numVars < dec.call.Index+1 { 293 dec.numVars = dec.call.Index + 1 294 } 295 for _, copyout := range dec.call.Copyout { 296 dec.numVars = max(dec.numVars, copyout.Index+1) 297 } 298 dec.calls = append(dec.calls, dec.call) 299 dec.call = ExecCall{} 300 } 301 302 func (dec *execDecoder) addStat(stat string, n int) { 303 if dec.stats == nil { 304 return 305 } 306 prefix := "" 307 for _, part := range strings.Split(stat, "/") { 308 dec.stats[prefix+part] += n 309 prefix += part + "/" 310 } 311 }