github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/prog_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  	"strings"
    11  	"testing"
    12  
    13  	"github.com/google/syzkaller/pkg/testutil"
    14  )
    15  
    16  func TestGeneration(t *testing.T) {
    17  	target, rs, iters := initTest(t)
    18  	ct := target.DefaultChoiceTable()
    19  	for i := 0; i < iters; i++ {
    20  		target.Generate(rs, 20, ct)
    21  	}
    22  }
    23  
    24  func TestDefault(t *testing.T) {
    25  	target, _, _ := initTest(t)
    26  	ForeachType(target.Syscalls, func(typ Type, ctx *TypeCtx) {
    27  		arg := typ.DefaultArg(ctx.Dir)
    28  		if !isDefault(arg) {
    29  			t.Errorf("default arg is not default: %s\ntype: %#v\narg: %#v",
    30  				typ, typ, arg)
    31  		}
    32  	})
    33  }
    34  
    35  func TestDefaultCallArgs(t *testing.T) {
    36  	testEachTarget(t, func(t *testing.T, target *Target) {
    37  		for _, meta := range target.SyscallMap {
    38  			if meta.Attrs.Disabled {
    39  				continue
    40  			}
    41  			// Ensure that we can restore all arguments of all calls.
    42  			prog := fmt.Sprintf("%v()", meta.Name)
    43  			p, err := target.Deserialize([]byte(prog), NonStrict)
    44  			if err != nil {
    45  				t.Fatalf("failed to restore default args in prog %q: %v", prog, err)
    46  			}
    47  			if len(p.Calls) != 1 || p.Calls[0].Meta.Name != meta.Name {
    48  				t.Fatalf("restored bad program from prog %q: %q", prog, p.Serialize())
    49  			}
    50  			s0 := string(p.Serialize())
    51  			p.sanitizeFix()
    52  			s1 := string(p.Serialize())
    53  			if s0 != s1 {
    54  				t.Fatalf("non-sanitized program or non-idempotent sanitize\nwas: %v\ngot: %v", s0, s1)
    55  			}
    56  		}
    57  	})
    58  }
    59  
    60  func testSerialize(t *testing.T, verbose bool) {
    61  	target, rs, iters := initTest(t)
    62  	ct := target.DefaultChoiceTable()
    63  	for i := 0; i < iters; i++ {
    64  		p := target.Generate(rs, 10, ct)
    65  		var data []byte
    66  		mode := NonStrict
    67  		if verbose {
    68  			data = p.SerializeVerbose()
    69  			mode = Strict
    70  		} else {
    71  			data = p.Serialize()
    72  		}
    73  		p1, err := target.Deserialize(data, mode)
    74  		if err != nil {
    75  			t.Fatalf("failed to deserialize program: %v\n%s", err, data)
    76  		}
    77  		if p1 == nil {
    78  			t.Fatalf("deserialized nil program:\n%s", data)
    79  		}
    80  		var data1 []byte
    81  		if verbose {
    82  			data1 = p1.SerializeVerbose()
    83  		} else {
    84  			data1 = p1.Serialize()
    85  		}
    86  		if len(p.Calls) != len(p1.Calls) {
    87  			t.Fatalf("different number of calls")
    88  		}
    89  		if !bytes.Equal(data, data1) {
    90  			t.Fatalf("program changed after serialize/deserialize\noriginal:\n%s\n\nnew:\n%s", data, data1)
    91  		}
    92  	}
    93  }
    94  
    95  func TestSerialize(t *testing.T) {
    96  	testSerialize(t, false)
    97  }
    98  
    99  func TestSerializeVerbose(t *testing.T) {
   100  	testSerialize(t, true)
   101  }
   102  
   103  func TestVmaType(t *testing.T) {
   104  	target, rs, iters := initRandomTargetTest(t, "test", "64")
   105  	ct := target.DefaultChoiceTable()
   106  	meta := target.SyscallMap["test$vma0"]
   107  	r := newRand(target, rs)
   108  	pageSize := target.PageSize
   109  	for i := 0; i < iters; i++ {
   110  		s := newState(target, ct, nil)
   111  		calls := r.generateParticularCall(s, meta)
   112  		c := calls[len(calls)-1]
   113  		if c.Meta.Name != "test$vma0" {
   114  			t.Fatalf("generated wrong call %v", c.Meta.Name)
   115  		}
   116  		if len(c.Args) != 6 {
   117  			t.Fatalf("generated wrong number of args %v", len(c.Args))
   118  		}
   119  		check := func(v, l Arg, min, max uint64) {
   120  			va, ok := v.(*PointerArg)
   121  			if !ok {
   122  				t.Fatalf("vma has bad type: %v", v)
   123  			}
   124  			la, ok := l.(*ConstArg)
   125  			if !ok {
   126  				t.Fatalf("len has bad type: %v", l)
   127  			}
   128  			if va.VmaSize < min || va.VmaSize > max {
   129  				t.Fatalf("vma has bad size: %v, want [%v-%v]",
   130  					va.VmaSize, min, max)
   131  			}
   132  			if la.Val < min || la.Val > max {
   133  				t.Fatalf("len has bad value: %v, want [%v-%v]",
   134  					la.Val, min, max)
   135  			}
   136  		}
   137  		check(c.Args[0], c.Args[1], 1*pageSize, 1e5*pageSize)
   138  		check(c.Args[2], c.Args[3], 5*pageSize, 5*pageSize)
   139  		check(c.Args[4], c.Args[5], 7*pageSize, 9*pageSize)
   140  	}
   141  }
   142  
   143  func TestFsckAttr(t *testing.T) {
   144  	target, err := GetTarget("test", "64")
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  
   149  	syscall := target.SyscallMap["test$fsck_attr"]
   150  	if syscall == nil {
   151  		t.Fatal("could not find test$fsck_attr in sys/test")
   152  	}
   153  
   154  	if syscall.Attrs.Fsck != "fsck.test -n" {
   155  		t.Fatalf("unexpected fsck command %s", syscall.Attrs.Fsck)
   156  	}
   157  }
   158  
   159  // TestCrossTarget ensures that a program serialized for one arch can be
   160  // deserialized for another arch. This happens when managers exchange
   161  // programs via hub.
   162  func TestCrossTarget(t *testing.T) {
   163  	if testutil.RaceEnabled {
   164  		t.Skip("skipping in race mode, too slow")
   165  	}
   166  	t.Parallel()
   167  	const OS = "linux"
   168  	var archs []string
   169  	for _, target := range AllTargets() {
   170  		if target.OS == OS {
   171  			archs = append(archs, target.Arch)
   172  		}
   173  	}
   174  	for _, arch := range archs {
   175  		target, err := GetTarget(OS, arch)
   176  		if err != nil {
   177  			t.Fatal(err)
   178  		}
   179  		var crossTargets []*Target
   180  		for _, crossArch := range archs {
   181  			if crossArch == arch {
   182  				continue
   183  			}
   184  			crossTarget, err := GetTarget(OS, crossArch)
   185  			if err != nil {
   186  				t.Fatal(err)
   187  			}
   188  			crossTargets = append(crossTargets, crossTarget)
   189  		}
   190  		t.Run(fmt.Sprintf("%v/%v", OS, arch), func(t *testing.T) {
   191  			t.Parallel()
   192  			testCrossTarget(t, target, crossTargets)
   193  		})
   194  	}
   195  }
   196  
   197  func testCrossTarget(t *testing.T, target *Target, crossTargets []*Target) {
   198  	ct := target.DefaultChoiceTable()
   199  	rs := testutil.RandSource(t)
   200  	iters := 100
   201  	if testing.Short() {
   202  		iters /= 10
   203  	}
   204  	for i := 0; i < iters; i++ {
   205  		p := target.Generate(rs, 20, ct)
   206  		testCrossArchProg(t, p, crossTargets)
   207  		p, err := target.Deserialize(p.Serialize(), NonStrict)
   208  		if err != nil {
   209  			t.Fatal(err)
   210  		}
   211  		testCrossArchProg(t, p, crossTargets)
   212  		p.Mutate(rs, 20, ct, nil, nil)
   213  		testCrossArchProg(t, p, crossTargets)
   214  		p, _ = Minimize(p, -1, MinimizeCorpus, func(*Prog, int) bool {
   215  			return rs.Int63()%2 == 0
   216  		})
   217  		testCrossArchProg(t, p, crossTargets)
   218  	}
   219  }
   220  
   221  func testCrossArchProg(t *testing.T, p *Prog, crossTargets []*Target) {
   222  	serialized := p.Serialize()
   223  	for _, crossTarget := range crossTargets {
   224  		_, err := crossTarget.Deserialize(serialized, NonStrict)
   225  		if err == nil || strings.Contains(err.Error(), "unknown syscall") {
   226  			continue
   227  		}
   228  		t.Fatalf("failed to deserialize for %v/%v: %v\n%s",
   229  			crossTarget.OS, crossTarget.Arch, err, serialized)
   230  	}
   231  }
   232  
   233  func TestSpecialStructs(t *testing.T) {
   234  	testEachTargetRandom(t, func(t *testing.T, target *Target, rs rand.Source, iters int) {
   235  		_ = target.GenerateAllSyzProg(rs)
   236  		ct := target.DefaultChoiceTable()
   237  		for special, gen := range target.SpecialTypes {
   238  			t.Run(special, func(t *testing.T) {
   239  				var typ Type
   240  				for i := 0; i < len(target.Syscalls) && typ == nil; i++ {
   241  					ForeachCallType(target.Syscalls[i], func(t Type, ctx *TypeCtx) {
   242  						if ctx.Dir == DirOut {
   243  							return
   244  						}
   245  						if s, ok := t.(*StructType); ok && s.Name() == special {
   246  							typ = s
   247  						}
   248  						if s, ok := t.(*UnionType); ok && s.Name() == special {
   249  							typ = s
   250  						}
   251  					})
   252  				}
   253  				if typ == nil {
   254  					t.Fatal("can't find struct description")
   255  				}
   256  				g := &Gen{newRand(target, rs), newState(target, ct, nil)}
   257  				for i := 0; i < iters/len(target.SpecialTypes); i++ {
   258  					var arg Arg
   259  					for i := 0; i < 2; i++ {
   260  						arg, _ = gen(g, typ, DirInOut, arg)
   261  						if arg.Dir() != DirInOut {
   262  							t.Fatalf("got wrong arg dir %v", arg.Dir())
   263  						}
   264  					}
   265  				}
   266  			})
   267  		}
   268  	})
   269  }
   270  
   271  func TestEscapingPaths(t *testing.T) {
   272  	paths := map[string]bool{
   273  		"/":                      true,
   274  		"/\x00":                  true,
   275  		"/file/..":               true,
   276  		"/file/../..":            true,
   277  		"./..":                   true,
   278  		"..":                     true,
   279  		"file/../../file":        true,
   280  		"../file":                true,
   281  		"./file/../../file/file": true,
   282  		"":                       false,
   283  		".":                      false,
   284  		"file":                   false,
   285  		"./file":                 false,
   286  		"./file/..":              false,
   287  	}
   288  	for path, want := range paths {
   289  		got := escapingFilename(path)
   290  		if got != want {
   291  			t.Errorf("path %q: got %v, want %v", path, got, want)
   292  		}
   293  	}
   294  }
   295  
   296  func TestFallbackSignal(t *testing.T) {
   297  	type desc struct {
   298  		prog string
   299  		info []CallInfo
   300  	}
   301  	tests := []desc{
   302  		// Test restored errno values and that non-executed syscalls don't get fallback signal.
   303  		{
   304  			`
   305  fallback$0()
   306  fallback$0()
   307  fallback$0()
   308  `,
   309  			[]CallInfo{
   310  				{
   311  					Flags:  CallExecuted,
   312  					Errno:  0,
   313  					Signal: make([]uint64, 1),
   314  				},
   315  				{
   316  					Flags:  CallExecuted,
   317  					Errno:  42,
   318  					Signal: make([]uint64, 1),
   319  				},
   320  				{},
   321  			},
   322  		},
   323  		// Test different cases of argument-dependent signal and that unsuccessful calls don't get it.
   324  		{
   325  			`
   326  r0 = fallback$0()
   327  fallback$1(r0)
   328  fallback$1(r0)
   329  fallback$1(0xffffffffffffffff)
   330  fallback$1(0x0)
   331  fallback$1(0x0)
   332  `,
   333  			[]CallInfo{
   334  				{
   335  					Flags:  CallExecuted,
   336  					Errno:  0,
   337  					Signal: make([]uint64, 1),
   338  				},
   339  				{
   340  					Flags:  CallExecuted,
   341  					Errno:  1,
   342  					Signal: make([]uint64, 1),
   343  				},
   344  				{
   345  					Flags:  CallExecuted,
   346  					Errno:  0,
   347  					Signal: make([]uint64, 2),
   348  				},
   349  				{
   350  					Flags:  CallExecuted,
   351  					Errno:  0,
   352  					Signal: make([]uint64, 1),
   353  				},
   354  				{
   355  					Flags:  CallExecuted,
   356  					Errno:  0,
   357  					Signal: make([]uint64, 2),
   358  				},
   359  				{
   360  					Flags:  CallExecuted,
   361  					Errno:  2,
   362  					Signal: make([]uint64, 1),
   363  				},
   364  			},
   365  		},
   366  		// Test that calls get no signal after a successful seccomp.
   367  		{
   368  			`
   369  fallback$0()
   370  fallback$0()
   371  breaks_returns()
   372  fallback$0()
   373  breaks_returns()
   374  fallback$0()
   375  fallback$0()
   376  `,
   377  			[]CallInfo{
   378  				{
   379  					Flags:  CallExecuted,
   380  					Errno:  0,
   381  					Signal: make([]uint64, 1),
   382  				},
   383  				{
   384  					Flags:  CallExecuted,
   385  					Errno:  0,
   386  					Signal: make([]uint64, 1),
   387  				},
   388  				{
   389  					Flags:  CallExecuted,
   390  					Errno:  1,
   391  					Signal: make([]uint64, 1),
   392  				},
   393  				{
   394  					Flags: CallExecuted,
   395  					Errno: 0,
   396  				},
   397  				{
   398  					Flags: CallExecuted,
   399  					Errno: 0,
   400  				},
   401  				{
   402  					Flags: CallExecuted,
   403  				},
   404  				{
   405  					Flags: CallExecuted,
   406  				},
   407  			},
   408  		},
   409  		{
   410  			`
   411  fallback$0()
   412  breaks_returns()
   413  fallback$0()
   414  breaks_returns()
   415  fallback$0()
   416  `,
   417  			[]CallInfo{
   418  				{
   419  					Flags:  CallExecuted,
   420  					Errno:  0,
   421  					Signal: make([]uint64, 1),
   422  				},
   423  				{
   424  					Flags:  CallExecuted,
   425  					Errno:  1,
   426  					Signal: make([]uint64, 1),
   427  				},
   428  				{
   429  					Flags: CallExecuted,
   430  					Errno: 0,
   431  				},
   432  				{
   433  					Flags: CallExecuted,
   434  					Errno: 0,
   435  				},
   436  				{
   437  					Flags: CallExecuted,
   438  				},
   439  			},
   440  		},
   441  	}
   442  	target, err := GetTarget("test", "64")
   443  	if err != nil {
   444  		t.Fatal(err)
   445  	}
   446  	for i, test := range tests {
   447  		t.Run(fmt.Sprint(i), func(t *testing.T) {
   448  			p, err := target.Deserialize([]byte(test.prog), Strict)
   449  			if err != nil {
   450  				t.Fatal(err)
   451  			}
   452  			if len(p.Calls) != len(test.info) {
   453  				t.Fatalf("call=%v info=%v", len(p.Calls), len(test.info))
   454  			}
   455  			wantSignal := make([]int, len(test.info))
   456  			for i := range test.info {
   457  				wantSignal[i] = len(test.info[i].Signal)
   458  				test.info[i].Signal = nil
   459  			}
   460  			p.FallbackSignal(test.info)
   461  			for i := range test.info {
   462  				if len(test.info[i].Signal) != wantSignal[i] {
   463  					t.Errorf("call %v: signal=%v want=%v", i, len(test.info[i].Signal), wantSignal[i])
   464  				}
   465  				for _, sig := range test.info[i].Signal {
   466  					call, errno := DecodeFallbackSignal(sig)
   467  					if call != p.Calls[i].Meta.ID {
   468  						t.Errorf("call %v: sig=%x id=%v want=%v", i, sig, call, p.Calls[i].Meta.ID)
   469  					}
   470  					if errno != test.info[i].Errno {
   471  						t.Errorf("call %v: sig=%x errno=%v want=%v", i, sig, errno, test.info[i].Errno)
   472  					}
   473  				}
   474  			}
   475  		})
   476  	}
   477  }
   478  
   479  func TestSanitizeRandom(t *testing.T) {
   480  	testEachTargetRandom(t, func(t *testing.T, target *Target, rs rand.Source, iters int) {
   481  		ct := target.DefaultChoiceTable()
   482  		for i := 0; i < iters; i++ {
   483  			p := target.Generate(rs, 10, ct)
   484  			s0 := string(p.Serialize())
   485  			p.sanitizeFix()
   486  			s1 := string(p.Serialize())
   487  			if s0 != s1 {
   488  				t.Fatalf("non-sanitized program or non-idempotent sanitize\nwas: %v\ngot: %v", s0, s1)
   489  			}
   490  		}
   491  	})
   492  }