1// Copyright 2016 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 4package prog 5 6import ( 7 "bytes" 8 "encoding/binary" 9 "fmt" 10 "reflect" 11 "testing" 12) 13 14func TestSerializeForExecRandom(t *testing.T) { 15 target, rs, iters := initTest(t) 16 buf := make([]byte, ExecBufferSize) 17 for i := 0; i < iters; i++ { 18 p := target.Generate(rs, 10, nil) 19 n, err := p.SerializeForExec(buf) 20 if err != nil { 21 t.Fatalf("failed to serialize: %v", err) 22 } 23 _, err = target.DeserializeExec(buf[:n]) 24 if err != nil { 25 t.Fatal(err) 26 } 27 } 28} 29 30func TestSerializeForExec(t *testing.T) { 31 target := initTargetTest(t, "test", "64") 32 var ( 33 dataOffset = target.DataOffset 34 ptrSize = target.PtrSize 35 ) 36 callID := func(name string) uint64 { 37 c := target.SyscallMap[name] 38 if c == nil { 39 t.Fatalf("unknown syscall %v", name) 40 } 41 return uint64(c.ID) 42 } 43 tests := []struct { 44 prog string 45 serialized []uint64 46 decoded *ExecProg 47 }{ 48 { 49 "test()", 50 []uint64{ 51 callID("test"), ExecNoCopyout, 0, 52 execInstrEOF, 53 }, 54 &ExecProg{ 55 Calls: []ExecCall{ 56 { 57 Meta: target.SyscallMap["test"], 58 Index: ExecNoCopyout, 59 }, 60 }, 61 }, 62 }, 63 { 64 "test$int(0x1, 0x2, 0x3, 0x4, 0x5)", 65 []uint64{ 66 callID("test$int"), ExecNoCopyout, 5, 67 execArgConst, 8, 1, 68 execArgConst, 1, 2, 69 execArgConst, 2, 3, 70 execArgConst, 4, 4, 71 execArgConst, 8, 5, 72 execInstrEOF, 73 }, 74 nil, 75 }, 76 { 77 "test$align0(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})", 78 []uint64{ 79 execInstrCopyin, dataOffset + 0, execArgConst, 2, 1, 80 execInstrCopyin, dataOffset + 4, execArgConst, 4, 2, 81 execInstrCopyin, dataOffset + 8, execArgConst, 1, 3, 82 execInstrCopyin, dataOffset + 10, execArgConst, 2, 4, 83 execInstrCopyin, dataOffset + 16, execArgConst, 8, 5, 84 callID("test$align0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 85 execInstrEOF, 86 }, 87 nil, 88 }, 89 { 90 "test$align1(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})", 91 []uint64{ 92 execInstrCopyin, dataOffset + 0, execArgConst, 2, 1, 93 execInstrCopyin, dataOffset + 2, execArgConst, 4, 2, 94 execInstrCopyin, dataOffset + 6, execArgConst, 1, 3, 95 execInstrCopyin, dataOffset + 7, execArgConst, 2, 4, 96 execInstrCopyin, dataOffset + 9, execArgConst, 8, 5, 97 callID("test$align1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 98 execInstrEOF, 99 }, 100 nil, 101 }, 102 { 103 "test$align2(&(0x7f0000000000)={0x42, {[0x43]}, {[0x44]}})", 104 []uint64{ 105 execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 106 execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43, 107 execInstrCopyin, dataOffset + 4, execArgConst, 2, 0x44, 108 callID("test$align2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 109 execInstrEOF, 110 }, 111 nil, 112 }, 113 { 114 "test$align3(&(0x7f0000000000)={0x42, {0x43}, {0x44}})", 115 []uint64{ 116 execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 117 execInstrCopyin, dataOffset + 1, execArgConst, 1, 0x43, 118 execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44, 119 callID("test$align3"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 120 execInstrEOF, 121 }, 122 nil, 123 }, 124 { 125 "test$align4(&(0x7f0000000000)={{0x42, 0x43}, 0x44})", 126 []uint64{ 127 execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 128 execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43, 129 execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44, 130 callID("test$align4"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 131 execInstrEOF, 132 }, 133 nil, 134 }, 135 { 136 "test$align5(&(0x7f0000000000)={{0x42, []}, {0x43, [0x44, 0x45, 0x46]}, 0x47})", 137 []uint64{ 138 execInstrCopyin, dataOffset + 0, execArgConst, 8, 0x42, 139 execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x43, 140 execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x44, 141 execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x45, 142 execInstrCopyin, dataOffset + 20, execArgConst, 2, 0x46, 143 execInstrCopyin, dataOffset + 22, execArgConst, 1, 0x47, 144 callID("test$align5"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 145 execInstrEOF, 146 }, 147 nil, 148 }, 149 { 150 "test$align6(&(0x7f0000000000)={0x42, [0x43]})", 151 []uint64{ 152 execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 153 execInstrCopyin, dataOffset + 4, execArgConst, 4, 0x43, 154 callID("test$align6"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 155 execInstrEOF, 156 }, 157 nil, 158 }, 159 { 160 "test$union0(&(0x7f0000000000)={0x1, @f2=0x2})", 161 []uint64{ 162 execInstrCopyin, dataOffset + 0, execArgConst, 8, 1, 163 execInstrCopyin, dataOffset + 8, execArgConst, 1, 2, 164 callID("test$union0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 165 execInstrEOF, 166 }, 167 nil, 168 }, 169 { 170 "test$union1(&(0x7f0000000000)={@f1=0x42, 0x43})", 171 []uint64{ 172 execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 173 execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x43, 174 callID("test$union1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 175 execInstrEOF, 176 }, 177 nil, 178 }, 179 { 180 "test$union2(&(0x7f0000000000)={@f1=0x42, 0x43})", 181 []uint64{ 182 execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 183 execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x43, 184 callID("test$union2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 185 execInstrEOF, 186 }, 187 nil, 188 }, 189 { 190 "test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})", 191 []uint64{ 192 execInstrCopyin, dataOffset + 0, execArgConst, 1, 1, 193 execInstrCopyin, dataOffset + 1, execArgConst, 2, 2, 194 execInstrCopyin, dataOffset + 3, execArgConst, 8, 3, 195 execInstrCopyin, dataOffset + 11, execArgConst, 8, 4, 196 callID("test$array0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 197 execInstrEOF, 198 }, 199 nil, 200 }, 201 { 202 "test$array1(&(0x7f0000000000)={0x42, \"0102030405\"})", 203 []uint64{ 204 execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 205 execInstrCopyin, dataOffset + 1, execArgData, 5, 0x0504030201, 206 callID("test$array1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 207 execInstrEOF, 208 }, 209 nil, 210 }, 211 { 212 "test$array2(&(0x7f0000000000)={0x42, \"aaaaaaaabbbbbbbbccccccccdddddddd\", 0x43})", 213 []uint64{ 214 execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42, 215 execInstrCopyin, dataOffset + 2, execArgData, 16, 0xbbbbbbbbaaaaaaaa, 0xddddddddcccccccc, 216 execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43, 217 callID("test$array2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 218 execInstrEOF, 219 }, 220 nil, 221 }, 222 { 223 "test$end0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42})", 224 []uint64{ 225 execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 226 execInstrCopyin, dataOffset + 1, execArgConst, 2 | 1<<8, 0x42, 227 execInstrCopyin, dataOffset + 3, execArgConst, 4 | 1<<8, 0x42, 228 execInstrCopyin, dataOffset + 7, execArgConst, 8 | 1<<8, 0x42, 229 callID("test$end0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 230 execInstrEOF, 231 }, 232 nil, 233 }, 234 { 235 "test$end1(&(0x7f0000000000)={0xe, 0x42, 0x1})", 236 []uint64{ 237 execInstrCopyin, dataOffset + 0, execArgConst, 2 | 1<<8, 0xe, 238 execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x42, 239 execInstrCopyin, dataOffset + 6, execArgConst, 8 | 1<<8, 0x1, 240 callID("test$end1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 241 execInstrEOF, 242 }, 243 nil, 244 }, 245 { 246 "test$bf0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})", 247 []uint64{ 248 execInstrCopyin, dataOffset + 0, execArgConst, 2 | 0<<16 | 10<<24, 0x42, 249 execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x42, 250 execInstrCopyin, dataOffset + 16, execArgConst, 2 | 0<<16 | 5<<24, 0x42, 251 execInstrCopyin, dataOffset + 16, execArgConst, 2 | 5<<16 | 6<<24, 0x42, 252 execInstrCopyin, dataOffset + 20, execArgConst, 4 | 0<<16 | 15<<24, 0x42, 253 execInstrCopyin, dataOffset + 24, execArgConst, 2 | 0<<16 | 11<<24, 0x42, 254 execInstrCopyin, dataOffset + 26, execArgConst, 2 | 1<<8 | 0<<16 | 11<<24, 0x42, 255 execInstrCopyin, dataOffset + 28, execArgConst, 1, 0x42, 256 callID("test$bf0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 257 execInstrEOF, 258 }, 259 &ExecProg{ 260 Calls: []ExecCall{ 261 { 262 Meta: target.SyscallMap["test$bf0"], 263 Index: ExecNoCopyout, 264 Args: []ExecArg{ 265 ExecArgConst{ 266 Size: ptrSize, 267 Value: dataOffset, 268 }, 269 }, 270 Copyin: []ExecCopyin{ 271 { 272 Addr: dataOffset + 0, 273 Arg: ExecArgConst{ 274 Size: 2, 275 Value: 0x42, 276 BitfieldOffset: 0, 277 BitfieldLength: 10, 278 }, 279 }, 280 { 281 Addr: dataOffset + 8, 282 Arg: ExecArgConst{ 283 Size: 8, 284 Value: 0x42, 285 }, 286 }, 287 { 288 Addr: dataOffset + 16, 289 Arg: ExecArgConst{ 290 Size: 2, 291 Value: 0x42, 292 BitfieldOffset: 0, 293 BitfieldLength: 5, 294 }, 295 }, 296 { 297 Addr: dataOffset + 16, 298 Arg: ExecArgConst{ 299 Size: 2, 300 Value: 0x42, 301 BitfieldOffset: 5, 302 BitfieldLength: 6, 303 }, 304 }, 305 { 306 Addr: dataOffset + 20, 307 Arg: ExecArgConst{ 308 Size: 4, 309 Value: 0x42, 310 BitfieldOffset: 0, 311 BitfieldLength: 15, 312 }, 313 }, 314 { 315 Addr: dataOffset + 24, 316 Arg: ExecArgConst{ 317 Size: 2, 318 Value: 0x42, 319 BitfieldOffset: 0, 320 BitfieldLength: 11, 321 }, 322 }, 323 { 324 Addr: dataOffset + 26, 325 Arg: ExecArgConst{ 326 Size: 2, 327 Format: FormatBigEndian, 328 Value: 0x42, 329 BitfieldOffset: 0, 330 BitfieldLength: 11, 331 }, 332 }, 333 { 334 Addr: dataOffset + 28, 335 Arg: ExecArgConst{ 336 Size: 1, 337 Value: 0x42, 338 }, 339 }, 340 }, 341 }, 342 }, 343 }, 344 }, 345 { 346 "test$bf1(&(0x7f0000000000)={{0x42, 0x42, 0x42}, 0x42})", 347 []uint64{ 348 execInstrCopyin, dataOffset + 0, execArgConst, 4 | 0<<16 | 10<<24, 0x42, 349 execInstrCopyin, dataOffset + 0, execArgConst, 4 | 10<<16 | 10<<24, 0x42, 350 execInstrCopyin, dataOffset + 0, execArgConst, 4 | 20<<16 | 10<<24, 0x42, 351 execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x42, 352 callID("test$bf1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 353 execInstrEOF, 354 }, 355 nil, 356 }, 357 { 358 "test$res1(0xffff)", 359 []uint64{ 360 callID("test$res1"), ExecNoCopyout, 1, execArgConst, 4, 0xffff, 361 execInstrEOF, 362 }, 363 nil, 364 }, 365 { 366 "test$opt3(0x0)", 367 []uint64{ 368 callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8 | 4<<32, 0x64, 369 execInstrEOF, 370 }, 371 nil, 372 }, 373 { 374 // Special value that translates to 0 for all procs. 375 "test$opt3(0xffffffffffffffff)", 376 []uint64{ 377 callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8, 0, 378 execInstrEOF, 379 }, 380 nil, 381 }, 382 { 383 // NULL pointer must be encoded os 0. 384 "test$opt1(0x0)", 385 []uint64{ 386 callID("test$opt1"), ExecNoCopyout, 1, execArgConst, 8, 0, 387 execInstrEOF, 388 }, 389 nil, 390 }, 391 { 392 "test$align7(&(0x7f0000000000)={{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, 0x42})", 393 []uint64{ 394 execInstrCopyin, dataOffset + 0, execArgConst, 1 | 0<<16 | 1<<24, 0x1, 395 execInstrCopyin, dataOffset + 0, execArgConst, 1 | 1<<16 | 1<<24, 0x2, 396 execInstrCopyin, dataOffset + 0, execArgConst, 1 | 2<<16 | 1<<24, 0x3, 397 execInstrCopyin, dataOffset + 1, execArgConst, 2 | 0<<16 | 1<<24, 0x4, 398 execInstrCopyin, dataOffset + 1, execArgConst, 2 | 1<<16 | 1<<24, 0x5, 399 execInstrCopyin, dataOffset + 1, execArgConst, 2 | 2<<16 | 1<<24, 0x6, 400 execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x42, 401 callID("test$align7"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 402 execInstrEOF, 403 }, 404 nil, 405 }, 406 } 407 408 buf := make([]byte, ExecBufferSize) 409 for i, test := range tests { 410 i, test := i, test 411 t.Run(fmt.Sprintf("%v:%v", i, test.prog), func(t *testing.T) { 412 p, err := target.Deserialize([]byte(test.prog)) 413 if err != nil { 414 t.Fatalf("failed to deserialize prog %v: %v", i, err) 415 } 416 n, err := p.SerializeForExec(buf) 417 if err != nil { 418 t.Fatalf("failed to serialize: %v", err) 419 } 420 w := new(bytes.Buffer) 421 binary.Write(w, binary.LittleEndian, test.serialized) 422 data := buf[:n] 423 if !bytes.Equal(data, w.Bytes()) { 424 got := make([]uint64, len(data)/8) 425 binary.Read(bytes.NewReader(data), binary.LittleEndian, &got) 426 t.Logf("want: %v", test.serialized) 427 t.Logf("got: %v", got) 428 t.Fatalf("mismatch") 429 } 430 decoded, err := target.DeserializeExec(data) 431 if err != nil { 432 t.Fatal(err) 433 } 434 if test.decoded != nil && !reflect.DeepEqual(decoded, *test.decoded) { 435 t.Logf("want: %#v", *test.decoded) 436 t.Logf("got: %#v", decoded) 437 t.Fatalf("decoded mismatch") 438 } 439 }) 440 } 441} 442