github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/subsystem/extractor_test.go (about)

     1  // Copyright 2023 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 subsystem
     5  
     6  import (
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func TestExtractor(t *testing.T) {
    14  	// Objects used in tests.
    15  	fsPath, mmFsPath := "fs/", "mm/fs.c"
    16  	extProg, nfsProg, extNfsProg := []byte("ext"), []byte("nfs"), []byte("ext nfs")
    17  	all := &Subsystem{Name: "fs"}
    18  	fs := &Subsystem{Name: "fs", Parents: []*Subsystem{all}}
    19  	ext := &Subsystem{Name: "ext", Parents: []*Subsystem{fs}}
    20  	nfs := &Subsystem{Name: "nfs", Parents: []*Subsystem{fs}}
    21  	mm := &Subsystem{Name: "mm", Parents: []*Subsystem{all}}
    22  	// Tests themselves.
    23  	tests := []struct {
    24  		name    string
    25  		crashes []*Crash
    26  		want    []*Subsystem
    27  	}{
    28  		{
    29  			name: `Make sure it works fine with just a single path`,
    30  			crashes: []*Crash{
    31  				{
    32  					GuiltyPath: fsPath,
    33  				},
    34  			},
    35  			want: []*Subsystem{fs},
    36  		},
    37  		{
    38  			name: `Make sure a child shadows its parent`,
    39  			crashes: []*Crash{
    40  				{
    41  					GuiltyPath: fsPath,
    42  				},
    43  				{
    44  					GuiltyPath: fsPath,
    45  					SyzRepro:   extProg,
    46  				},
    47  			},
    48  			want: []*Subsystem{ext},
    49  		},
    50  		{
    51  			name: `Reproducers hint at different subsystems`,
    52  			crashes: []*Crash{
    53  				{
    54  					GuiltyPath: fsPath,
    55  				},
    56  				{
    57  					GuiltyPath: fsPath,
    58  					SyzRepro:   extProg,
    59  				},
    60  				{
    61  					GuiltyPath: fsPath,
    62  					SyzRepro:   nfsProg,
    63  				},
    64  			},
    65  			want: []*Subsystem{fs},
    66  		},
    67  		{
    68  			name: `One subsystem from reproducers is irrelevant`,
    69  			crashes: []*Crash{
    70  				{
    71  					GuiltyPath: fsPath,
    72  				},
    73  				{
    74  					GuiltyPath: fsPath,
    75  					SyzRepro:   extProg,
    76  				},
    77  				{
    78  					GuiltyPath: fsPath,
    79  					SyzRepro:   extNfsProg,
    80  				},
    81  			},
    82  			want: []*Subsystem{ext},
    83  		},
    84  		{
    85  			name: `Reproducer supporting one of guilty paths`,
    86  			crashes: []*Crash{
    87  				// The guilty paths correspond both to mm and fs.
    88  				{
    89  					GuiltyPath: mmFsPath,
    90  				},
    91  				{
    92  					GuiltyPath: mmFsPath,
    93  				},
    94  				{
    95  					GuiltyPath: mmFsPath,
    96  				},
    97  				{
    98  					// But one reproducer points clearly to fs.
    99  					GuiltyPath: mmFsPath,
   100  					SyzRepro:   extProg,
   101  				},
   102  			},
   103  			want: []*Subsystem{ext},
   104  		},
   105  	}
   106  	extractor := &Extractor{
   107  		raw: &testRawExtractor{
   108  			perPath: map[string][]*Subsystem{
   109  				fsPath:   {fs},
   110  				mmFsPath: {mm, fs},
   111  			},
   112  			perProg: []progSubsystems{
   113  				{extProg, []*Subsystem{ext}},
   114  				{nfsProg, []*Subsystem{nfs}},
   115  				{extNfsProg, []*Subsystem{ext, nfs}},
   116  			},
   117  		},
   118  	}
   119  	for _, test := range tests {
   120  		ret := extractor.Extract(test.crashes)
   121  		assert.ElementsMatch(t, ret, test.want, test.name)
   122  	}
   123  }
   124  
   125  type testRawExtractor struct {
   126  	perPath map[string][]*Subsystem
   127  	perProg []progSubsystems
   128  }
   129  
   130  type progSubsystems struct {
   131  	prog []byte
   132  	ret  []*Subsystem
   133  }
   134  
   135  func (e *testRawExtractor) FromPath(path string) []*Subsystem {
   136  	return e.perPath[path]
   137  }
   138  
   139  func (e *testRawExtractor) FromProg(progBytes []byte) []*Subsystem {
   140  	for _, obj := range e.perProg {
   141  		if reflect.DeepEqual(progBytes, obj.prog) {
   142  			return obj.ret
   143  		}
   144  	}
   145  	return nil
   146  }