github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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 := determineCommitInfo(*flagKernelRepo)
    62  	code, err := generateSubsystemsFile(*flagName, list, commitInfo)
    63  	if err != nil {
    64  		tool.Failf("failed to generate code: %s", err)
    65  	}
    66  	err = osutil.WriteFile(filepath.Join(folder, *flagName+".go"), code)
    67  	if err != nil {
    68  		tool.Failf("failed to save the code: %s", err)
    69  	}
    70  }
    71  
    72  func postProcessList(list []*subsystem.Subsystem) []*subsystem.Subsystem {
    73  	if *flagFilter != "" {
    74  		list = subsystem.FilterList(list, prepareFilter())
    75  	}
    76  	if !*flagEmails {
    77  		for _, item := range list {
    78  			item.Lists = nil
    79  			item.Maintainers = nil
    80  		}
    81  	}
    82  	return list
    83  }
    84  
    85  func prepareFilter() func(*subsystem.Subsystem) bool {
    86  	keep := map[string]bool{}
    87  	for _, name := range strings.Split(*flagFilter, ",") {
    88  		name = strings.TrimSpace(name)
    89  		if name != "" {
    90  			keep[name] = true
    91  		}
    92  	}
    93  	return func(s *subsystem.Subsystem) bool {
    94  		return keep[s.Name]
    95  	}
    96  }
    97  
    98  func determineCommitInfo(dir string) string {
    99  	// Best effort only.
   100  	repo, err := vcs.NewRepo(*flagOS, "", dir, vcs.OptPrecious, vcs.OptDontSandbox)
   101  	if err != nil {
   102  		return fmt.Sprintf("failed to open repo: %v", err)
   103  	}
   104  	commit, err := repo.HeadCommit()
   105  	if err != nil {
   106  		return fmt.Sprintf("failed to get HEAD commit: %v", err)
   107  	}
   108  	return fmt.Sprintf(`Commit %s, "%.32s"`, commit.Hash, commit.Title)
   109  }