github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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  			"tmpfs": {"syz_mount_image$tmpfs"},
   240  		},
   241  		extraSubsystems: map[string][]string{
   242  			"udf": {"UDF FILESYSTEM"},
   243  		},
   244  	}
   245  	testMaintainers = `
   246  Maintainers List
   247  ----------------
   248  
   249  .. note:: When reading this list, please look for the most precise areas
   250            first. When adding to this list, please keep the entries in
   251            alphabetical order.
   252  
   253  FILESYSTEMS (VFS and infrastructure)
   254  M:	Developer <email_vfs@email.com>
   255  L:	linux-fsdevel@vger.kernel.org
   256  S:	Maintained
   257  F:	fs/*
   258  F:	include/linux/fs.h
   259  F:	include/linux/fs_types.h
   260  F:	include/uapi/linux/fs.h
   261  F:	include/uapi/linux/openat2.h
   262  
   263  EXT4 FILE SYSTEM
   264  M:	Developer <email_ext4@email.com>
   265  M:	Developer <email_ext4_2@email.com>
   266  L:	linux-ext4@vger.kernel.org
   267  S:	Maintained
   268  W:	http://ext4.wiki.kernel.org
   269  Q:	http://patchwork.ozlabs.org/project/linux-ext4/list/
   270  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git
   271  F:	Documentation/filesystems/ext4/
   272  F:	fs/ext4/
   273  F:	include/trace/events/ext4.h
   274  
   275  FREEVXFS FILESYSTEM
   276  M:	Developer <email_vxfs@email.com>
   277  S:	Maintained
   278  W:	ftp://ftp.openlinux.org/pub/people/hch/vxfs
   279  F:	fs/freevxfs/
   280  
   281  MEMORY MANAGEMENT
   282  M:	Developer <email_mm@email.com>
   283  L:	linux-mm@kvack.org
   284  S:	Maintained
   285  W:	http://www.linux-mm.org
   286  T:	git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
   287  T:	quilt git://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new
   288  F:	include/linux/gfp.h
   289  F:	include/linux/gfp_types.h
   290  F:	include/linux/memory_hotplug.h
   291  F:	include/linux/mm.h
   292  F:	include/linux/mmzone.h
   293  F:	include/linux/pagewalk.h
   294  F:	include/linux/vmalloc.h
   295  F:	mm/
   296  F:	tools/testing/selftests/vm/
   297  
   298  TMPFS (SHMEM FILESYSTEM)
   299  M:	Developer <email_shmem@email.com>
   300  L:	tmpfs@kvack.org
   301  S:	Maintained
   302  F:	include/linux/shmem_fs.h
   303  F:	mm/shmem*
   304  
   305  UDF FILESYSTEM
   306  M:	email_udf <email_udf@email.com>
   307  L:	linux-fsdevel@vger.kernel.org
   308  S:	Maintained
   309  F:	Documentation/filesystems/udf.rst
   310  F:	fs/udf/
   311  
   312  THE REST
   313  M:	Developer <email_rest@email.com>
   314  L:	linux-kernel@vger.kernel.org
   315  S:	Buried alive in reporters
   316  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
   317  F:	*
   318  F:	*/
   319  
   320  `
   321  )