github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/mutation_test.go (about) 1 // Copyright 2015 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 "bytes" 8 "fmt" 9 "math/rand" 10 "testing" 11 12 "github.com/google/syzkaller/pkg/testutil" 13 ) 14 15 func TestMutationFlags(t *testing.T) { 16 tests := [][2]string{ 17 // Mutate flags (bitmask = true). 18 { 19 `r0 = mutate_flags(&(0x7f0000000000)="2e2f66696c653000", 0x0, 0x1, 0x1)`, 20 `r0 = mutate_flags(&(0x7f0000000000)="2e2f66696c653000", 0x20, 0x1, 0x9)`, 21 }, 22 { 23 `r0 = mutate_flags2(&(0x7f0000000000)="2e2f66696c653000", 0x0)`, 24 `r0 = mutate_flags2(&(0x7f0000000000)="2e2f66696c653000", 0xd9)`, 25 }, 26 // Mutate flags (bitmask = false). 27 { 28 `r0 = mutate_flags3(&(0x7f0000000000)="2e2f66696c653000", 0x0)`, 29 `r0 = mutate_flags3(&(0x7f0000000000)="2e2f66696c653000", 0xddddeeee)`, 30 }, 31 { 32 `r0 = mutate_flags3(&(0x7f0000000000)="2e2f66696c653000", 0xddddeeee)`, 33 `r0 = mutate_flags3(&(0x7f0000000000)="2e2f66696c653000", 0xaaaaaaaa)`, 34 }, 35 } 36 runMutationTests(t, tests, true) 37 } 38 39 func TestChooseCall(t *testing.T) { 40 tests := [][2]string{ 41 // The call with many arguments has a higher mutation probability. 42 { 43 `mutate0() 44 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 45 mutate_integer2(0x00, 0x00, 0x20, 0x00, 0x01)`, 46 `mutate0() 47 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0xffffffff) 48 mutate_integer2(0x00, 0x00, 0x20, 0x00, 0x01)`, 49 }, 50 // Calls with the same probability. 51 { 52 `mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 53 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 54 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 55 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 56 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1)`, 57 `mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 58 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 59 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0xff) 60 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 61 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1)`, 62 }, 63 // The call with a lower probability can be mutated. 64 { 65 `mutate7(&(0x7f0000000000)='123', 0x3) 66 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 67 r0 = mutate_flags(&(0x7f0000000000)="2e2f66696c653000", 0x0, 0x1, 0x1)`, 68 `mutate7(&(0x7f0000000000)='123', 0x2) 69 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1) 70 r0 = mutate_flags(&(0x7f0000000000)="2e2f66696c653000", 0x0, 0x1, 0x1)`, 71 }, 72 // Complex arguments. 73 { 74 `test$struct(&(0x7f0000000000)={0x0, {0x0}}) 75 test$array0(&(0x7f0000001000)={0x1, [@f0=0x2, @f1=0x3], 0x4}) 76 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1)`, 77 `test$struct(&(0x7f0000000000)={0xff, {0x0}}) 78 test$array0(&(0x7f0000001000)={0x1, [@f0=0x2, @f1=0x3], 0x4}) 79 mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1)`, 80 }, 81 } 82 runMutationTests(t, tests, true) 83 } 84 85 func TestMutateArgument(t *testing.T) { 86 if testutil.RaceEnabled { 87 t.Skip("skipping in race mode, too slow") 88 } 89 // nolint: lll 90 tests := [][2]string{ 91 // Mutate an integer with a higher priority than the boolean arguments. 92 { 93 `mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1)`, 94 `mutate_integer(0x0, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0xffffffff)`, 95 }, 96 // Mutate a boolean. 97 { 98 `mutate_integer(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)`, 99 `mutate_integer(0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0)`, 100 }, 101 // Mutate flags (bitmask = true). 102 { 103 `r0 = mutate_flags(&(0x7f0000000000)="2e2f66696c653000", 0x0, 0x1, 0x1)`, 104 `r0 = mutate_flags(&(0x7f0000000000)="2e2f66696c653000", 0x20, 0x1, 0x9)`, 105 }, 106 // Mutate an int8 from a set of other arguments with higher priority. 107 { 108 `mutate_integer2(0x00, 0x00, 0x20, 0x00, 0x01)`, 109 `mutate_integer2(0x00, 0x00, 0x20, 0x00, 0x07)`, 110 }, 111 // Mutate an array of structs. 112 { 113 `mutate_array2(&(0x7f0000000000)=[{0x0}, {0x0}, {0x0}, {0x0}, {0x0}])`, 114 `mutate_array2(&(0x7f0000000000)=[{0x0}, {0x0}, {0x3}, {0x0}, {0x0}])`, 115 }, 116 // Mutate a non-special union that have more than 1 option. 117 { 118 `mutate_union(&(0x7f0000000000)=@f1=[0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x0, 0x0])`, 119 `mutate_union(&(0x7f0000000000)=@f0=0x2)`, 120 }, 121 // Mutate the value of the current option in union. 122 { 123 `mutate_union(&(0x7f0000000000)=@f1=[0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x0, 0x0])`, 124 `mutate_union(&(0x7f0000000000)=@f1=[0x0, 0x1, 0xff, 0x3, 0x0, 0x1, 0x2, 0x3, 0x0, 0x0])`, 125 }, 126 // Mutate filename using target.SpecialFileLenghts. 127 { 128 `mutate9(&(0x7f0000000000)='./file0\x00')`, 129 `mutate9(&(0x7f0000000040)='./file0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x00')`, 130 }, 131 { 132 `mutate10(&(0x7f0000000000)=""/10)`, 133 `mutate10(&(0x7f0000000040)=""/256)`, 134 }, 135 } 136 137 target := initTargetTest(t, "test", "64") 138 for ti, test := range tests { 139 t.Run(fmt.Sprint(ti), func(t *testing.T) { 140 t.Parallel() 141 rs, ct, p, goal, err := buildTestContext(test, target) 142 if err != nil { 143 t.Fatalf("failed to deserialize the program: %v", err) 144 } 145 want := goal.Serialize() 146 for i := 0; i < 1e5; i++ { 147 p1 := p.Clone() 148 ctx := &mutator{ 149 p: p1, 150 r: newRand(p1.Target, rs), 151 ncalls: 2 * len(p.Calls), 152 ct: ct, 153 corpus: nil, 154 opts: DefaultMutateOpts, 155 } 156 ctx.mutateArg() 157 data1 := p1.Serialize() 158 if bytes.Equal(want, data1) { 159 t.Logf("success on iter %v", i) 160 return 161 } 162 } 163 t.Fatalf("failed to achieve goal, original:%s\ngoal:%s", test[0], test[1]) 164 }) 165 } 166 } 167 168 func TestMutateNoSquash(t *testing.T) { 169 target := initTargetTest(t, "test", "64") 170 p, err := target.Deserialize([]byte(`mutate_no_squash(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, "5e9ce23b"})`), Strict) 171 if err != nil { 172 t.Fatal(err) 173 } 174 rs := rand.NewSource(0) 175 r := newRand(target, rs) 176 ctx := &mutator{ 177 p: p, 178 r: r, 179 ncalls: 1, 180 ct: target.DefaultChoiceTable(), 181 opts: DefaultMutateOpts, 182 } 183 184 // squashAny should not mutate the program. 185 for i := 0; i < 100; i++ { 186 p1 := p.Clone() 187 ctx.p = p1 188 if ctx.squashAny() { 189 t.Fatalf("squashAny mutated a no_squash call: %s", p1.Serialize()) 190 } 191 } 192 } 193 194 func TestSizeMutateArg(t *testing.T) { 195 target, rs, iters := initRandomTargetTest(t, "test", "64") 196 r := newRand(target, rs) 197 ct := target.DefaultChoiceTable() 198 for i := 0; i < iters; i++ { 199 p := target.Generate(rs, 10, ct) 200 for it := 0; it < 10; it++ { 201 p1 := p.Clone() 202 ctx := &mutator{ 203 p: p1, 204 r: r, 205 ncalls: 2 * len(p.Calls), 206 ct: ct, 207 corpus: nil, 208 opts: DefaultMutateOpts, 209 } 210 ctx.mutateArg() 211 ForeachArg(p.Calls[0], func(arg Arg, ctx *ArgCtx) { 212 if _, ok := arg.Type().(*IntType); !ok { 213 return 214 } 215 bits := arg.Type().TypeBitSize() 216 limit := uint64(1<<bits - 1) 217 val := arg.(*ConstArg).Val 218 if val > limit { 219 t.Fatalf("invalid argument value: %d. (arg size: %d; max value: %d)", val, arg.Size(), limit) 220 } 221 }) 222 } 223 } 224 } 225 226 func TestClone(t *testing.T) { 227 target, rs, iters := initTest(t) 228 ct := target.DefaultChoiceTable() 229 for i := 0; i < iters; i++ { 230 p := target.Generate(rs, 10, ct) 231 p1 := p.Clone() 232 data := p.Serialize() 233 data1 := p1.Serialize() 234 if !bytes.Equal(data, data1) { 235 t.Fatalf("program changed after clone\noriginal:\n%s\n\nnew:\n%s", data, data1) 236 } 237 } 238 } 239 240 func TestMutateRandom(t *testing.T) { 241 testEachTargetRandom(t, func(t *testing.T, target *Target, rs rand.Source, iters int) { 242 ct := target.DefaultChoiceTable() 243 next: 244 for i := 0; i < iters; i++ { 245 p := target.Generate(rs, 10, ct) 246 data0 := p.Serialize() 247 p1 := p.Clone() 248 // There is a chance that mutation will produce the same program. 249 // So we check that at least 1 out of 20 mutations actually change the program. 250 for try := 0; try < 20; try++ { 251 p1.Mutate(rs, 10, ct, nil, nil) 252 data := p.Serialize() 253 if !bytes.Equal(data0, data) { 254 t.Fatalf("program changed after mutate\noriginal:\n%s\n\nnew:\n%s", 255 data0, data) 256 } 257 data1 := p1.Serialize() 258 if bytes.Equal(data, data1) { 259 continue 260 } 261 if _, err := target.Deserialize(data1, NonStrict); err != nil { 262 t.Fatalf("deserialize failed after mutate: %v\n%s", err, data1) 263 } 264 continue next 265 } 266 t.Fatalf("mutation does not change program:\n%s", data0) 267 } 268 }) 269 } 270 271 func TestMutateCorpus(t *testing.T) { 272 target, rs, iters := initTest(t) 273 ct := target.DefaultChoiceTable() 274 var corpus []*Prog 275 for i := 0; i < 100; i++ { 276 p := target.Generate(rs, 10, ct) 277 corpus = append(corpus, p) 278 } 279 for i := 0; i < iters; i++ { 280 p1 := target.Generate(rs, 10, ct) 281 p1.Mutate(rs, 10, ct, nil, corpus) 282 } 283 } 284 285 func TestMutateTable(t *testing.T) { 286 tests := [][2]string{ 287 // Insert a call. 288 {` 289 mutate0() 290 mutate2() 291 `, ` 292 mutate0() 293 mutate1() 294 mutate2() 295 `}, 296 // Remove calls and update args. 297 {` 298 r0 = mutate5(&(0x7f0000000000)="2e2f66696c653000", 0x0) 299 mutate0() 300 mutate6(r0, &(0x7f0000000000)="00", 0x1) 301 mutate1() 302 `, ` 303 mutate0() 304 mutate6(0xffffffffffffffff, &(0x7f0000000000)="00", 0x1) 305 mutate1() 306 `}, 307 // Mutate flags. 308 {` 309 r0 = mutate5(&(0x7f0000000000)="2e2f66696c653000", 0x0) 310 mutate0() 311 mutate6(r0, &(0x7f0000000000)="00", 0x1) 312 mutate1() 313 `, ` 314 r0 = mutate5(&(0x7f0000000000)="2e2f66696c653000", 0xcdcdcdcd) 315 mutate0() 316 mutate6(r0, &(0x7f0000000000)="00", 0x1) 317 mutate1() 318 `}, 319 // Mutate data (delete byte and update size). 320 {` 321 mutate4(&(0x7f0000000000)="11223344", 0x4) 322 `, ` 323 mutate4(&(0x7f0000000000)="113344", 0x3) 324 `}, 325 // Mutate data (change byte). 326 {` 327 mutate4(&(0x7f0000000000)="1122", 0x2) 328 `, ` 329 mutate4(&(0x7f0000000000)="1100", 0x2) 330 `}, 331 // Change filename. 332 {` 333 mutate5(&(0x7f0000001000)="2e2f66696c653000", 0x22c0) 334 mutate5(&(0x7f0000001000)="2e2f66696c653000", 0x22c0) 335 `, ` 336 mutate5(&(0x7f0000001000)="2e2f66696c653000", 0x22c0) 337 mutate5(&(0x7f0000001000)="2e2f66696c653100", 0x22c0) 338 `}, 339 // Mutate the array. 340 {` 341 mutate_array(0x1, 0x30, &(0x7f0000000000)=[0x1, 0x1, 0x1, 0x1, 0x1]) 342 `, ` 343 mutate_array(0x1, 0x30, &(0x7f0000000000)=[0x1, 0x1, 0x1, 0x1]) 344 `}, 345 // Extend an array. 346 {` 347 mutate3(&(0x7f0000000000)=[0x1, 0x1], 0x2) 348 `, ` 349 mutate3(&(0x7f0000000000)=[0x1, 0x1, 0x1], 0x3) 350 `}, 351 // Mutate size from it's natural value. 352 {` 353 mutate7(&(0x7f0000000000)='123', 0x3) 354 `, ` 355 mutate7(&(0x7f0000000000)='123', 0x2) 356 `}, 357 // Mutate proc to the special value. 358 {` 359 mutate8(0x2) 360 `, ` 361 mutate8(0xffffffffffffffff) 362 `}, 363 // Increase buffer length. 364 {` 365 mutate_buffer(&(0x7f0000000000)=""/100) 366 `, ` 367 mutate_buffer(&(0x7f0000000000)=""/200) 368 `}, 369 // Decrease buffer length. 370 {` 371 mutate_buffer(&(0x7f0000000000)=""/800) 372 `, ` 373 mutate_buffer(&(0x7f0000000000)=""/4) 374 `}, 375 // Mutate a ranged buffer. 376 {` 377 mutate_rangedbuffer(&(0x7f00000000c0)=""/10) 378 `, ` 379 mutate_rangedbuffer(&(0x7f00000000c0)=""/7) 380 `}, 381 } 382 383 runMutationTests(t, tests, true) 384 } 385 386 func TestNegativeMutations(t *testing.T) { 387 tests := [][2]string{ 388 // Mutate buffer size outside the range limits. 389 {` 390 mutate_rangedbuffer(&(0x7f00000000c0)=""/7) 391 `, ` 392 mutate_rangedbuffer(&(0x7f00000000c0)=""/4) 393 `}, 394 {` 395 mutate_rangedbuffer(&(0x7f00000000c0)=""/7) 396 `, ` 397 mutate_rangedbuffer(&(0x7f00000000c0)=""/11) 398 `}, 399 } 400 runMutationTests(t, tests, false) 401 } 402 403 func BenchmarkMutate(b *testing.B) { 404 target, cleanup := initBench(b) 405 defer cleanup() 406 ct := target.DefaultChoiceTable() 407 const progLen = 30 408 p := target.Generate(rand.NewSource(0), progLen, ct) 409 b.ResetTimer() 410 b.RunParallel(func(pb *testing.PB) { 411 rs := rand.NewSource(0) 412 for pb.Next() { 413 p.Clone().Mutate(rs, progLen, ct, nil, nil) 414 } 415 }) 416 } 417 418 func BenchmarkGenerate(b *testing.B) { 419 target, cleanup := initBench(b) 420 defer cleanup() 421 ct := target.DefaultChoiceTable() 422 const progLen = 30 423 b.ResetTimer() 424 b.RunParallel(func(pb *testing.PB) { 425 rs := rand.NewSource(0) 426 for pb.Next() { 427 target.Generate(rs, progLen, ct) 428 } 429 }) 430 } 431 432 func runMutationTests(t *testing.T, tests [][2]string, valid bool) { 433 if testutil.RaceEnabled { 434 t.Skip("skipping in race mode, too slow") 435 } 436 target := initTargetTest(t, "test", "64") 437 for ti, test := range tests { 438 t.Run(fmt.Sprint(ti), func(t *testing.T) { 439 t.Parallel() 440 rs, ct, p, goal, err := buildTestContext(test, target) 441 if err != nil { 442 t.Fatalf("failed to deserialize the program: %v", err) 443 } 444 want := goal.Serialize() 445 iters := testutil.IterCount() 446 if valid { 447 iters = 1e6 // it will stop after reaching the goal 448 } 449 for i := 0; i < iters; i++ { 450 p1 := p.Clone() 451 p1.Mutate(rs, len(goal.Calls), ct, nil, nil) 452 data1 := p1.Serialize() 453 if bytes.Equal(want, data1) { 454 if !valid { 455 t.Fatalf("failed on iter %v", i) 456 } 457 t.Logf("success on iter %v", i) 458 return 459 } 460 } 461 if valid { 462 t.Fatalf("failed to achieve goal, original:%s\ngoal:%s", test[0], test[1]) 463 } 464 }) 465 } 466 } 467 468 func buildTestContext(test [2]string, target *Target) (rs rand.Source, ct *ChoiceTable, p, goal *Prog, err error) { 469 p, err = target.Deserialize([]byte(test[0]), Strict) 470 if err != nil { 471 return 472 } 473 goal, err = target.Deserialize([]byte(test[1]), Strict) 474 if err != nil { 475 return 476 } 477 enabled := make(map[*Syscall]bool) 478 for _, c := range p.Calls { 479 enabled[c.Meta] = true 480 } 481 for _, c := range goal.Calls { 482 enabled[c.Meta] = true 483 } 484 ct = target.BuildChoiceTable(nil, enabled) 485 rs = rand.NewSource(0) 486 return 487 } 488 489 func BenchmarkStoreLoadInt(b *testing.B) { 490 // To get unaligned data on heap (compiler manages to align it on stack). 491 data := make([]byte, 9) 492 sink = data 493 data = sink.([]byte)[1:] 494 for i := 0; i < b.N; i++ { 495 for size := 1; size <= 8; size *= 2 { 496 storeInt(data, uint64(i), size) 497 v := loadInt(data, size) 498 if uint8(v) != uint8(i) { 499 panic("bad") 500 } 501 } 502 } 503 } 504 505 var sink interface{}