github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/any_test.go (about)

     1  // Copyright 2018 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  	"fmt"
     8  	"math/rand"
     9  	"sort"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/google/syzkaller/pkg/testutil"
    14  )
    15  
    16  func TestIsComplexPtr(t *testing.T) {
    17  	testEachTargetRandom(t, func(t *testing.T, target *Target, rs rand.Source, iters int) {
    18  		allComplex := make(map[string]bool)
    19  		ForeachType(target.Syscalls, func(t Type, ctx *TypeCtx) {
    20  			if ptr, ok := t.(*PtrType); ok && ptr.SquashableElem {
    21  				allComplex[ptr.Elem.String()] = true
    22  			}
    23  		})
    24  		var arr []string
    25  		for id := range allComplex {
    26  			arr = append(arr, id)
    27  		}
    28  		sort.Strings(arr)
    29  		// Log all complex types for manual inspection.
    30  		t.Log("complex types:\n" + strings.Join(arr, "\n"))
    31  		if testing.Short() || testutil.RaceEnabled {
    32  			return
    33  		}
    34  		// Compare with what we can generate at runtime.
    35  		// We cannot guarantee that we will generate 100% of complex types
    36  		// (some are no_generate, and the process is random), but we should
    37  		// generate at least 90% or there is something wrong.
    38  		ct := target.DefaultChoiceTable()
    39  		r := newRand(target, rs)
    40  		generatedComplex := make(map[string]bool)
    41  		for _, meta := range target.Syscalls {
    42  			if meta.Attrs.Disabled || meta.Attrs.NoGenerate {
    43  				continue
    44  			}
    45  			for i := 0; i < 10; i++ {
    46  				s := newState(target, ct, nil)
    47  				calls := r.generateParticularCall(s, meta)
    48  				p := &Prog{Target: target, Calls: calls}
    49  				for _, arg := range p.complexPtrs() {
    50  					generatedComplex[arg.arg.Res.Type().String()] = true
    51  				}
    52  			}
    53  		}
    54  		for id := range generatedComplex {
    55  			if !allComplex[id] {
    56  				t.Errorf("generated complex %v that is not statically complex", id)
    57  			}
    58  		}
    59  		for id := range allComplex {
    60  			if !generatedComplex[id] {
    61  				t.Logf("did not generate %v", id)
    62  			}
    63  		}
    64  		if len(generatedComplex) < len(allComplex)*9/10 {
    65  			t.Errorf("generated too few complex types: %v/%v", len(generatedComplex), len(allComplex))
    66  		}
    67  	})
    68  }
    69  
    70  func TestSquash(t *testing.T) {
    71  	target := initTargetTest(t, "test", "64")
    72  	// nolint: lll
    73  	tests := []struct {
    74  		prog     string
    75  		squashed string // leave empty if the arg must not be squashed
    76  	}{
    77  		{
    78  			`foo$any_in(&(0x7f0000000000)={0x11, 0x11223344, 0x2233, 0x1122334455667788, {0x1, 0x7, 0x1, 0x1, 0x1bc, 0x4}, [{@res32=0x0, @i8=0x44, "aabb"}, {@res64=0x1, @i32=0x11223344, "1122334455667788"}, {@res8=0x2, @i8=0x55, "cc"}]})`,
    79  			`foo$any_in(&(0x7f0000000000)=ANY=[@ANYBLOB="1100000044332211223300000000000088776655443322117d00bc11", @ANYRES32=0x0, @ANYBLOB="0000000044aabb00", @ANYRES64=0x1, @ANYBLOB="443322111122334455667788", @ANYRES8=0x2, @ANYBLOB="0000000000000055cc0000"])`,
    80  		},
    81  		{
    82  			// Inout pointers must not be squashed.
    83  			`foo$any_inout(&(0x7f0000000000)={0x11, 0x11223344, 0x2233, 0x1122334455667788, {0x1, 0x7, 0x1, 0x1, 0x1bc, 0x4}, [{@res32=0x0, @i8=0x44, "aabb"}, {@res64=0x1, @i32=0x11223344, "1122334455667788"}, {@res8=0x2, @i8=0x55, "cc"}]})`,
    84  			``,
    85  		},
    86  		{
    87  			// Squashing of structs with out_overlay is not supported yet
    88  			// (used to panic, see isComplexPtr).
    89  			`
    90  overlay_any(&(0x7f0000000000)=@overlay2={0x0, 0x0, <r0=>0x0, 0x0})
    91  overlay_uses(0x0, 0x0, 0x0, r0)
    92  `,
    93  			``,
    94  		},
    95  		{
    96  			// Unions with filenames must not be squashed.
    97  			`foo$any_filename(&AUTO)`,
    98  			``,
    99  		},
   100  	}
   101  	for i, test := range tests {
   102  		t.Run(fmt.Sprint(i), func(t *testing.T) {
   103  			p, err := target.Deserialize([]byte(test.prog), Strict)
   104  			if err != nil {
   105  				t.Fatalf("failed to deserialize prog: %v", err)
   106  			}
   107  			ptrArg := p.Calls[0].Args[0].(*PointerArg)
   108  			if test.squashed == "" {
   109  				if target.isComplexPtr(ptrArg) {
   110  					t.Fatalf("arg is complex and can be squashed")
   111  				}
   112  				return
   113  			}
   114  			if !target.isComplexPtr(ptrArg) {
   115  				t.Fatalf("arg is not complex")
   116  			}
   117  			if target.ArgContainsAny(ptrArg) {
   118  				t.Fatalf("arg is already squashed")
   119  			}
   120  			target.squashPtr(ptrArg)
   121  			if !target.ArgContainsAny(ptrArg) {
   122  				t.Fatalf("arg is not squashed")
   123  			}
   124  			p1 := strings.TrimSpace(string(p.Serialize()))
   125  			target.squashPtr(ptrArg)
   126  			p2 := strings.TrimSpace(string(p.Serialize()))
   127  			if p1 != p2 {
   128  				t.Fatalf("double squash changed program:\n%v\nvs:\n%v", p1, p2)
   129  			}
   130  			if p1 != test.squashed {
   131  				t.Fatalf("bad squash result:\n%v\nwant:\n%v", p1, test.squashed)
   132  			}
   133  		})
   134  	}
   135  }