github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/tools/syz-query-subsystems/query_subsystems.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  // syz-query-subsystems generates and saves the subsystem lists in the format syzkaller understands.
     5  // An example how to generate the linux subsystem list (for the upstream kernel).
     6  // `./syz-query-subsystems -os linux -kernel ~/linux -syzkaller ~/syzkaller -name linux`.
     7  
     8  package main
     9  
    10  import (
    11  	"flag"
    12  	"fmt"
    13  	"path/filepath"
    14  	"regexp"
    15  	"strings"
    16  
    17  	"github.com/google/syzkaller/pkg/osutil"
    18  	"github.com/google/syzkaller/pkg/subsystem"
    19  	"github.com/google/syzkaller/pkg/subsystem/linux"
    20  	"github.com/google/syzkaller/pkg/tool"
    21  	"github.com/google/syzkaller/pkg/vcs"
    22  )
    23  
    24  var (
    25  	flagOS            = flag.String("os", "", "target OS type")
    26  	flagKernelRepo    = flag.String("kernel", "", "path to the OS kernel source directory")
    27  	flagSyzkallerRepo = flag.String("syzkaller", "", "path to the syzkaller repo")
    28  	flagName          = flag.String("name", "", "the name under which the list should be saved")
    29  	flagFilter        = flag.String("filter", "", "comma-separated list of subsystems to keep")
    30  	flagEmails        = flag.Bool("emails", true, "save lists and maintainer fields")
    31  )
    32  
    33  var nameRe = regexp.MustCompile(`^[a-z]\w*$`)
    34  
    35  func main() {
    36  	defer tool.Init()()
    37  	// Validate the input.
    38  	if strings.ToLower(*flagOS) != "linux" {
    39  		tool.Failf("only Linux is supported at the moment")
    40  	}
    41  	if !osutil.IsExist(*flagKernelRepo) {
    42  		tool.Failf("the specified kernel repo does not exist")
    43  	}
    44  	if !osutil.IsExist(*flagSyzkallerRepo) {
    45  		tool.Failf("the specified syzkaller repo does not exist")
    46  	}
    47  	if !nameRe.MatchString(*flagName) {
    48  		tool.Failf("the name is not acceptable")
    49  	}
    50  	// Query the subsystems.
    51  	list, err := linux.ListFromRepo(*flagKernelRepo)
    52  	if err != nil {
    53  		tool.Failf("failed to query subsystems: %v", err)
    54  	}
    55  	list = postProcessList(list)
    56  	// Save the list.
    57  	folder := filepath.Join(*flagSyzkallerRepo, "pkg", "subsystem", "lists")
    58  	if err = osutil.MkdirAll(folder); err != nil {
    59  		tool.Failf("failed to create %s: %v", folder, err)
    60  	}
    61  	commitInfo, err := determineCommitInfo(*flagKernelRepo)
    62  	if err != nil {
    63  		tool.Failf("failed to fetch commit info: %v", err)
    64  	}
    65  	code, err := generateSubsystemsFile(*flagName, list, commitInfo)
    66  	if err != nil {
    67  		tool.Failf("failed to generate code: %s", err)
    68  	}
    69  	err = osutil.WriteFile(filepath.Join(folder, *flagName+".go"), code)
    70  	if err != nil {
    71  		tool.Failf("failed to save the code: %s", err)
    72  	}
    73  }
    74  
    75  func postProcessList(list []*subsystem.Subsystem) []*subsystem.Subsystem {
    76  	if *flagFilter != "" {
    77  		list = subsystem.FilterList(list, prepareFilter())
    78  	}
    79  	if !*flagEmails {
    80  		for _, item := range list {
    81  			item.Lists = nil
    82  			item.Maintainers = nil
    83  		}
    84  	}
    85  	return list
    86  }
    87  
    88  func prepareFilter() func(*subsystem.Subsystem) bool {
    89  	keep := map[string]bool{}
    90  	for _, name := range strings.Split(*flagFilter, ",") {
    91  		name = strings.TrimSpace(name)
    92  		if name != "" {
    93  			keep[name] = true
    94  		}
    95  	}
    96  	return func(s *subsystem.Subsystem) bool {
    97  		return keep[s.Name]
    98  	}
    99  }
   100  
   101  func determineCommitInfo(dir string) (*vcs.Commit, error) {
   102  	repo, err := vcs.NewRepo(*flagOS, "", dir, vcs.OptPrecious, vcs.OptDontSandbox)
   103  	if err != nil {
   104  		return nil, fmt.Errorf("failed to open repo: %w", err)
   105  	}
   106  	commit, err := repo.Commit(vcs.HEAD)
   107  	if err != nil {
   108  		return nil, fmt.Errorf("failed to get HEAD commit: %w", err)
   109  	}
   110  	return commit, err
   111  }