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{}