github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/subsystem/linux/subsystems_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 linux
     5  
     6  import (
     7  	"io/fs"
     8  	"testing"
     9  	"testing/fstest"
    10  
    11  	"github.com/google/syzkaller/pkg/subsystem"
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  func TestGroupLinuxSubsystems(t *testing.T) {
    16  	subsystems, err := listFromRepoInner(
    17  		prepareTestLinuxRepo(t, []byte(testMaintainers)),
    18  		nil)
    19  	if err != nil {
    20  		t.Fatal(err)
    21  	}
    22  	for _, s := range subsystems {
    23  		// The regexps used for matching rules may change later, so let's not compare them here.
    24  		s.PathRules = nil
    25  		// It complicates the test, so let's skip it here.
    26  		s.Parents = nil
    27  	}
    28  	expected := []*subsystem.Subsystem{
    29  		{
    30  			Name:  "fs",
    31  			Lists: []string{"linux-fsdevel@vger.kernel.org"},
    32  			// Two different subsystems point to linux-fsdevel@vger.kernel.org, so
    33  			// we do not include maintainers.
    34  		},
    35  		{
    36  			Name:        "ext4",
    37  			Lists:       []string{"linux-ext4@vger.kernel.org"},
    38  			Maintainers: []string{"email_ext4@email.com", "email_ext4_2@email.com"},
    39  		},
    40  		{
    41  			Name:        "mm",
    42  			Lists:       []string{"linux-mm@kvack.org"},
    43  			Maintainers: []string{"email_mm@email.com"},
    44  		},
    45  		{
    46  			Name:        "tmpfs",
    47  			Lists:       []string{"tmpfs@kvack.org"},
    48  			Maintainers: []string{"email_shmem@email.com"},
    49  		},
    50  		{
    51  			Name:        "kernel",
    52  			Lists:       []string{"linux-kernel@vger.kernel.org"},
    53  			Maintainers: []string{"email_rest@email.com"},
    54  		},
    55  	}
    56  	assert.ElementsMatch(t, subsystems, expected)
    57  }
    58  
    59  func TestCustomCallRules(t *testing.T) {
    60  	subsystems, err := listFromRepoInner(
    61  		prepareTestLinuxRepo(t, []byte(testMaintainers)),
    62  		testRules,
    63  	)
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	for _, s := range subsystems {
    68  		// The regexps used for matching rules may change later, so let's not compare them here.
    69  		s.PathRules = nil
    70  		// It complicates the test, so let's skip it here.
    71  		s.Parents = nil
    72  	}
    73  	// Ensure that the subsystem from the custom rule is present.
    74  	assert.Contains(t, subsystems, &subsystem.Subsystem{
    75  		Name:        "udf",
    76  		Maintainers: []string{"email_udf@email.com"},
    77  		Lists:       []string{"linux-fsdevel@vger.kernel.org"},
    78  	})
    79  	// Now that udf is excluded, it becomes possible to generate a maintainer list for vfs.
    80  	assert.Contains(t, subsystems, &subsystem.Subsystem{
    81  		Name:        "fs",
    82  		Lists:       []string{"linux-fsdevel@vger.kernel.org"},
    83  		Maintainers: []string{"email_vfs@email.com"},
    84  	})
    85  
    86  	expectCalls := map[string][]string{
    87  		"ext4":  {"syz_mount_image$ext4"},
    88  		"tmpfs": {"syz_mount_image$tmpfs"},
    89  	}
    90  	gotCalls := map[string][]string{}
    91  	for _, s := range subsystems {
    92  		if len(s.Syscalls) > 0 {
    93  			gotCalls[s.Name] = s.Syscalls
    94  		}
    95  	}
    96  	assert.Equal(t, len(expectCalls), len(gotCalls))
    97  	for name, expect := range expectCalls {
    98  		assert.ElementsMatchf(t, expect, gotCalls[name], "syscalls of %s", name)
    99  	}
   100  }
   101  
   102  func TestLinuxSubsystemPaths(t *testing.T) {
   103  	// For the list of subsystems, see TestLinuxSubsystemsList.
   104  	// Here we rely on the same ones.
   105  	repo := prepareTestLinuxRepo(t, []byte(testMaintainers))
   106  	subsystems, err := listFromRepoInner(repo, nil)
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  	matcher := subsystem.MakePathMatcher(subsystems)
   111  	tests := []struct {
   112  		path string
   113  		list []string
   114  	}{
   115  		{
   116  			path: `fs/internal.h`,
   117  			list: []string{"kernel", "fs"},
   118  		},
   119  		{
   120  			path: `fs/ext4/mmp.c`,
   121  			list: []string{"kernel", "fs", "ext4"},
   122  		},
   123  		{
   124  			// The subsystem is not present in our test MAINTAINERS.
   125  			path: `fs/fat/inode.c`,
   126  			list: []string{"kernel", "fs"},
   127  		},
   128  		{
   129  			path: `fs/freevxfs/vxfs_olt.c`,
   130  			list: []string{"kernel", "fs"},
   131  		},
   132  		{
   133  			path: `mm/memory.c`,
   134  			list: []string{"kernel", "mm"},
   135  		},
   136  		{
   137  			path: `mm/shmem.c`,
   138  			list: []string{"kernel", "mm", "tmpfs"},
   139  		},
   140  		{
   141  			path: `include/net/ah.h`,
   142  			list: []string{"kernel"},
   143  		},
   144  		{
   145  			path: `include/linux/mm.h`,
   146  			list: []string{"kernel", "mm"},
   147  		},
   148  		{
   149  			path: `include/linux/fs.h`,
   150  			list: []string{"kernel", "fs"},
   151  		},
   152  	}
   153  	for _, test := range tests {
   154  		retList := []string{}
   155  		for _, s := range matcher.Match(test.path) {
   156  			retList = append(retList, s.Name)
   157  		}
   158  		assert.ElementsMatchf(t, retList, test.list,
   159  			"invalid subsystems for %#v", test.path)
   160  	}
   161  }
   162  
   163  func TestLinuxSubsystemParents(t *testing.T) {
   164  	// For the list of subsystems, see TestLinuxSubsystemsList.
   165  	// Here we rely on the same ones.
   166  	repo := prepareTestLinuxRepo(t, []byte(testMaintainers))
   167  	subsystems, err := listFromRepoInner(repo, nil)
   168  	if err != nil {
   169  		t.Fatal(err)
   170  	}
   171  	ensureParents(t, subsystems, map[string][]string{
   172  		"ext4":     {"fs"},
   173  		"mm":       {"kernel"},
   174  		"fs":       {"kernel"},
   175  		"tmpfs":    {"mm"},
   176  		"freevxfs": {"fs"},
   177  	})
   178  
   179  	// Now check that our custom parent rules work.
   180  	subsystems2, err := listFromRepoInner(repo, &customRules{
   181  		addParents: map[string][]string{
   182  			// Just for the sake of testing.
   183  			"fs": {"mm"},
   184  		},
   185  	})
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  	ensureParents(t, subsystems2, map[string][]string{
   190  		"ext4":     {"fs"},
   191  		"mm":       {"kernel"},
   192  		"fs":       {"mm"}, // We test for this change.
   193  		"tmpfs":    {"mm"},
   194  		"freevxfs": {"fs"},
   195  	})
   196  }
   197  
   198  func ensureParents(t *testing.T, subsystems []*subsystem.Subsystem,
   199  	expectParents map[string][]string) {
   200  	for _, s := range subsystems {
   201  		names := []string{}
   202  		for _, p := range s.Parents {
   203  			names = append(names, p.Name)
   204  		}
   205  		assert.ElementsMatch(t, names, expectParents[s.Name],
   206  			"wrong parents for %#v", s.Name)
   207  	}
   208  }
   209  
   210  func prepareTestLinuxRepo(t *testing.T, maintainers []byte) fs.FS {
   211  	return fstest.MapFS{
   212  		`fs/ext4/fsync.c`:          {},
   213  		`fs/ext4/fsync.h`:          {},
   214  		`fs/ext4/mmp.c`:            {},
   215  		`fs/ext4/mmp.h`:            {},
   216  		`fs/freevxfs/vxfs_olt.c`:   {},
   217  		`fs/freevxfs/vxfs_olt.h`:   {},
   218  		`fs/freevxfs/file.c`:       {},
   219  		`fs/udf/file.c`:            {},
   220  		`fs/udf/file2.c`:           {},
   221  		`fs/udf/file3.c`:           {},
   222  		`fs/file.c`:                {},
   223  		`fs/internal.h`:            {},
   224  		`include/linux/fs.h`:       {},
   225  		`include/linux/mm.h`:       {},
   226  		`include/linux/shmem_fs.h`: {},
   227  		`include/net/ah.h`:         {},
   228  		`mm/memory.c`:              {},
   229  		`mm/shmem.c`:               {},
   230  		`mm/shmem2.c`:              {},
   231  		`MAINTAINERS`:              {Data: maintainers},
   232  	}
   233  }
   234  
   235  var (
   236  	testRules = &customRules{
   237  		subsystemCalls: map[string][]string{
   238  			"ext4":  {"syz_mount_image$ext4"},
   239  			"vxfs":  {"syz_mount_image$vxfs"},
   240  			"tmpfs": {"syz_mount_image$tmpfs"},
   241  		},
   242  		extraSubsystems: map[string][]string{
   243  			"udf": {"UDF FILESYSTEM"},
   244  		},
   245  	}
   246  	testMaintainers = `
   247  Maintainers List
   248  ----------------
   249  
   250  .. note:: When reading this list, please look for the most precise areas
   251            first. When adding to this list, please keep the entries in
   252            alphabetical order.
   253  
   254  FILESYSTEMS (VFS and infrastructure)
   255  M:	Developer <email_vfs@email.com>
   256  L:	linux-fsdevel@vger.kernel.org
   257  S:	Maintained
   258  F:	fs/*
   259  F:	include/linux/fs.h
   260  F:	include/linux/fs_types.h
   261  F:	include/uapi/linux/fs.h
   262  F:	include/uapi/linux/openat2.h
   263  
   264  EXT4 FILE SYSTEM
   265  M:	Developer <email_ext4@email.com>
   266  M:	Developer <email_ext4_2@email.com>
   267  L:	linux-ext4@vger.kernel.org
   268  S:	Maintained
   269  W:	http://ext4.wiki.kernel.org
   270  Q:	http://patchwork.ozlabs.org/project/linux-ext4/list/
   271  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git
   272  F:	Documentation/filesystems/ext4/
   273  F:	fs/ext4/
   274  F:	include/trace/events/ext4.h
   275  
   276  FREEVXFS FILESYSTEM
   277  M:	Developer <email_vxfs@email.com>
   278  S:	Maintained
   279  W:	ftp://ftp.openlinux.org/pub/people/hch/vxfs
   280  F:	fs/freevxfs/
   281  
   282  MEMORY MANAGEMENT
   283  M:	Developer <email_mm@email.com>
   284  L:	linux-mm@kvack.org
   285  S:	Maintained
   286  W:	http://www.linux-mm.org
   287  T:	git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
   288  T:	quilt git://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new
   289  F:	include/linux/gfp.h
   290  F:	include/linux/gfp_types.h
   291  F:	include/linux/memory_hotplug.h
   292  F:	include/linux/mm.h
   293  F:	include/linux/mmzone.h
   294  F:	include/linux/pagewalk.h
   295  F:	include/linux/vmalloc.h
   296  F:	mm/
   297  F:	tools/testing/selftests/vm/
   298  
   299  TMPFS (SHMEM FILESYSTEM)
   300  M:	Developer <email_shmem@email.com>
   301  L:	tmpfs@kvack.org
   302  S:	Maintained
   303  F:	include/linux/shmem_fs.h
   304  F:	mm/shmem*
   305  
   306  UDF FILESYSTEM
   307  M:	email_udf <email_udf@email.com>
   308  L:	linux-fsdevel@vger.kernel.org
   309  S:	Maintained
   310  F:	Documentation/filesystems/udf.rst
   311  F:	fs/udf/
   312  
   313  THE REST
   314  M:	Developer <email_rest@email.com>
   315  L:	linux-kernel@vger.kernel.org
   316  S:	Buried alive in reporters
   317  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
   318  F:	*
   319  F:	*/
   320  
   321  `
   322  )