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