github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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 test := test 140 t.Run(fmt.Sprint(ti), func(t *testing.T) { 141 t.Parallel() 142 rs, ct, p, goal, err := buildTestContext(test, target) 143 if err != nil { 144 t.Fatalf("failed to deserialize the program: %v", err) 145 } 146 want := goal.Serialize() 147 for i := 0; i < 1e5; i++ { 148 p1 := p.Clone() 149 ctx := &mutator{ 150 p: p1, 151 r: newRand(p1.Target, rs), 152 ncalls: 2 * len(p.Calls), 153 ct: ct, 154 corpus: nil, 155 opts: DefaultMutateOpts, 156 } 157 ctx.mutateArg() 158 data1 := p1.Serialize() 159 if bytes.Equal(want, data1) { 160 t.Logf("success on iter %v", i) 161 return 162 } 163 } 164 t.Fatalf("failed to achieve goal, original:%s\ngoal:%s", test[0], test[1]) 165 }) 166 } 167 } 168 169 func TestSizeMutateArg(t *testing.T) { 170 target, rs, iters := initRandomTargetTest(t, "test", "64") 171 r := newRand(target, rs) 172 ct := target.DefaultChoiceTable() 173 for i := 0; i < iters; i++ { 174 p := target.Generate(rs, 10, ct) 175 for it := 0; it < 10; it++ { 176 p1 := p.Clone() 177 ctx := &mutator{ 178 p: p1, 179 r: r, 180 ncalls: 2 * len(p.Calls), 181 ct: ct, 182 corpus: nil, 183 opts: DefaultMutateOpts, 184 } 185 ctx.mutateArg() 186 ForeachArg(p.Calls[0], func(arg Arg, ctx *ArgCtx) { 187 if _, ok := arg.Type().(*IntType); !ok { 188 return 189 } 190 bits := arg.Type().TypeBitSize() 191 limit := uint64(1<<bits - 1) 192 val := arg.(*ConstArg).Val 193 if val > limit { 194 t.Fatalf("invalid argument value: %d. (arg size: %d; max value: %d)", val, arg.Size(), limit) 195 } 196 }) 197 } 198 } 199 } 200 201 func TestClone(t *testing.T) { 202 target, rs, iters := initTest(t) 203 ct := target.DefaultChoiceTable() 204 for i := 0; i < iters; i++ { 205 p := target.Generate(rs, 10, ct) 206 p1 := p.Clone() 207 data := p.Serialize() 208 data1 := p1.Serialize() 209 if !bytes.Equal(data, data1) { 210 t.Fatalf("program changed after clone\noriginal:\n%s\n\nnew:\n%s", data, data1) 211 } 212 } 213 } 214 215 func TestMutateRandom(t *testing.T) { 216 testEachTargetRandom(t, func(t *testing.T, target *Target, rs rand.Source, iters int) { 217 ct := target.DefaultChoiceTable() 218 next: 219 for i := 0; i < iters; i++ { 220 p := target.Generate(rs, 10, ct) 221 data0 := p.Serialize() 222 p1 := p.Clone() 223 // There is a chance that mutation will produce the same program. 224 // So we check that at least 1 out of 20 mutations actually change the program. 225 for try := 0; try < 20; try++ { 226 p1.Mutate(rs, 10, ct, nil, nil) 227 data := p.Serialize() 228 if !bytes.Equal(data0, data) { 229 t.Fatalf("program changed after mutate\noriginal:\n%s\n\nnew:\n%s", 230 data0, data) 231 } 232 data1 := p1.Serialize() 233 if bytes.Equal(data, data1) { 234 continue 235 } 236 if _, err := target.Deserialize(data1, NonStrict); err != nil { 237 t.Fatalf("deserialize failed after mutate: %v\n%s", err, data1) 238 } 239 continue next 240 } 241 t.Fatalf("mutation does not change program:\n%s", data0) 242 } 243 }) 244 } 245 246 func TestMutateCorpus(t *testing.T) { 247 target, rs, iters := initTest(t) 248 ct := target.DefaultChoiceTable() 249 var corpus []*Prog 250 for i := 0; i < 100; i++ { 251 p := target.Generate(rs, 10, ct) 252 corpus = append(corpus, p) 253 } 254 for i := 0; i < iters; i++ { 255 p1 := target.Generate(rs, 10, ct) 256 p1.Mutate(rs, 10, ct, nil, corpus) 257 } 258 } 259 260 func TestMutateTable(t *testing.T) { 261 tests := [][2]string{ 262 // Insert a call. 263 {` 264 mutate0() 265 mutate2() 266 `, ` 267 mutate0() 268 mutate1() 269 mutate2() 270 `}, 271 // Remove calls and update args. 272 {` 273 r0 = mutate5(&(0x7f0000000000)="2e2f66696c653000", 0x0) 274 mutate0() 275 mutate6(r0, &(0x7f0000000000)="00", 0x1) 276 mutate1() 277 `, ` 278 mutate0() 279 mutate6(0xffffffffffffffff, &(0x7f0000000000)="00", 0x1) 280 mutate1() 281 `}, 282 // Mutate flags. 283 {` 284 r0 = mutate5(&(0x7f0000000000)="2e2f66696c653000", 0x0) 285 mutate0() 286 mutate6(r0, &(0x7f0000000000)="00", 0x1) 287 mutate1() 288 `, ` 289 r0 = mutate5(&(0x7f0000000000)="2e2f66696c653000", 0xcdcdcdcd) 290 mutate0() 291 mutate6(r0, &(0x7f0000000000)="00", 0x1) 292 mutate1() 293 `}, 294 // Mutate data (delete byte and update size). 295 {` 296 mutate4(&(0x7f0000000000)="11223344", 0x4) 297 `, ` 298 mutate4(&(0x7f0000000000)="113344", 0x3) 299 `}, 300 // Mutate data (change byte). 301 {` 302 mutate4(&(0x7f0000000000)="1122", 0x2) 303 `, ` 304 mutate4(&(0x7f0000000000)="1100", 0x2) 305 `}, 306 // Change filename. 307 {` 308 mutate5(&(0x7f0000001000)="2e2f66696c653000", 0x22c0) 309 mutate5(&(0x7f0000001000)="2e2f66696c653000", 0x22c0) 310 `, ` 311 mutate5(&(0x7f0000001000)="2e2f66696c653000", 0x22c0) 312 mutate5(&(0x7f0000001000)="2e2f66696c653100", 0x22c0) 313 `}, 314 // Mutate the array. 315 {` 316 mutate_array(0x1, 0x30, &(0x7f0000000000)=[0x1, 0x1, 0x1, 0x1, 0x1]) 317 `, ` 318 mutate_array(0x1, 0x30, &(0x7f0000000000)=[0x1, 0x1, 0x1, 0x1]) 319 `}, 320 // Extend an array. 321 {` 322 mutate3(&(0x7f0000000000)=[0x1, 0x1], 0x2) 323 `, ` 324 mutate3(&(0x7f0000000000)=[0x1, 0x1, 0x1], 0x3) 325 `}, 326 // Mutate size from it's natural value. 327 {` 328 mutate7(&(0x7f0000000000)='123', 0x3) 329 `, ` 330 mutate7(&(0x7f0000000000)='123', 0x2) 331 `}, 332 // Mutate proc to the special value. 333 {` 334 mutate8(0x2) 335 `, ` 336 mutate8(0xffffffffffffffff) 337 `}, 338 // Increase buffer length. 339 {` 340 mutate_buffer(&(0x7f0000000000)=""/100) 341 `, ` 342 mutate_buffer(&(0x7f0000000000)=""/200) 343 `}, 344 // Decrease buffer length. 345 {` 346 mutate_buffer(&(0x7f0000000000)=""/800) 347 `, ` 348 mutate_buffer(&(0x7f0000000000)=""/4) 349 `}, 350 // Mutate a ranged buffer. 351 {` 352 mutate_rangedbuffer(&(0x7f00000000c0)=""/10) 353 `, ` 354 mutate_rangedbuffer(&(0x7f00000000c0)=""/7) 355 `}, 356 } 357 358 runMutationTests(t, tests, true) 359 } 360 361 func TestNegativeMutations(t *testing.T) { 362 tests := [][2]string{ 363 // Mutate buffer size outside the range limits. 364 {` 365 mutate_rangedbuffer(&(0x7f00000000c0)=""/7) 366 `, ` 367 mutate_rangedbuffer(&(0x7f00000000c0)=""/4) 368 `}, 369 {` 370 mutate_rangedbuffer(&(0x7f00000000c0)=""/7) 371 `, ` 372 mutate_rangedbuffer(&(0x7f00000000c0)=""/11) 373 `}, 374 } 375 runMutationTests(t, tests, false) 376 } 377 378 func BenchmarkMutate(b *testing.B) { 379 target, cleanup := initBench(b) 380 defer cleanup() 381 ct := target.DefaultChoiceTable() 382 const progLen = 30 383 p := target.Generate(rand.NewSource(0), progLen, ct) 384 b.ResetTimer() 385 b.RunParallel(func(pb *testing.PB) { 386 rs := rand.NewSource(0) 387 for pb.Next() { 388 p.Clone().Mutate(rs, progLen, ct, nil, nil) 389 } 390 }) 391 } 392 393 func BenchmarkGenerate(b *testing.B) { 394 target, cleanup := initBench(b) 395 defer cleanup() 396 ct := target.DefaultChoiceTable() 397 const progLen = 30 398 b.ResetTimer() 399 b.RunParallel(func(pb *testing.PB) { 400 rs := rand.NewSource(0) 401 for pb.Next() { 402 target.Generate(rs, progLen, ct) 403 } 404 }) 405 } 406 407 func runMutationTests(t *testing.T, tests [][2]string, valid bool) { 408 if testutil.RaceEnabled { 409 t.Skip("skipping in race mode, too slow") 410 } 411 target := initTargetTest(t, "test", "64") 412 for ti, test := range tests { 413 test := test 414 t.Run(fmt.Sprint(ti), func(t *testing.T) { 415 t.Parallel() 416 rs, ct, p, goal, err := buildTestContext(test, target) 417 if err != nil { 418 t.Fatalf("failed to deserialize the program: %v", err) 419 } 420 want := goal.Serialize() 421 iters := testutil.IterCount() 422 if valid { 423 iters = 1e6 // it will stop after reaching the goal 424 } 425 for i := 0; i < iters; i++ { 426 p1 := p.Clone() 427 p1.Mutate(rs, len(goal.Calls), ct, nil, nil) 428 data1 := p1.Serialize() 429 if bytes.Equal(want, data1) { 430 if !valid { 431 t.Fatalf("failed on iter %v", i) 432 } 433 t.Logf("success on iter %v", i) 434 return 435 } 436 } 437 if valid { 438 t.Fatalf("failed to achieve goal, original:%s\ngoal:%s", test[0], test[1]) 439 } 440 }) 441 } 442 } 443 444 func buildTestContext(test [2]string, target *Target) (rs rand.Source, ct *ChoiceTable, p, goal *Prog, err error) { 445 p, err = target.Deserialize([]byte(test[0]), Strict) 446 if err != nil { 447 return 448 } 449 goal, err = target.Deserialize([]byte(test[1]), Strict) 450 if err != nil { 451 return 452 } 453 enabled := make(map[*Syscall]bool) 454 for _, c := range p.Calls { 455 enabled[c.Meta] = true 456 } 457 for _, c := range goal.Calls { 458 enabled[c.Meta] = true 459 } 460 ct = target.BuildChoiceTable(nil, enabled) 461 rs = rand.NewSource(0) 462 return 463 } 464 465 func BenchmarkStoreLoadInt(b *testing.B) { 466 // To get unaligned data on heap (compiler manages to align it on stack). 467 data := make([]byte, 9) 468 sink = data 469 data = sink.([]byte)[1:] 470 for i := 0; i < b.N; i++ { 471 for size := 1; size <= 8; size *= 2 { 472 storeInt(data, uint64(i), size) 473 v := loadInt(data, size) 474 if uint8(v) != uint8(i) { 475 panic("bad") 476 } 477 } 478 } 479 } 480 481 var sink interface{}