github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-cluster/pkg/api/api.go (about)

     1  // Copyright 2024 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 api
     5  
     6  import "time"
     7  
     8  // The output passed to other workflow steps.
     9  type TriageResult struct {
    10  	// If set, ignore the patch series completely.
    11  	SkipReason string `json:"skip_reason"`
    12  	// Fuzzing configuration to try (NULL if nothing).
    13  	Fuzz []*FuzzTask `json:"fuzz"`
    14  }
    15  
    16  // The data layout faclitates the simplicity of the workflow definition.
    17  type FuzzTask struct {
    18  	Base    BuildRequest `json:"base"`
    19  	Patched BuildRequest `json:"patched"`
    20  	FuzzConfig
    21  }
    22  
    23  const (
    24  	FocusNet     = "net"
    25  	FocusKVM     = "kvm"
    26  	FocusIoUring = "io_uring"
    27  	FocusBPF     = "bpf"
    28  	FocusFS      = "fs"
    29  )
    30  
    31  // FuzzConfig represents a set of parameters passed to the fuzz step.
    32  // The triage step aggregates multiple KernelFuzzConfig to construct FuzzConfig.
    33  type FuzzConfig struct {
    34  	Track      string   `json:"track"` // E.g. KASAN.
    35  	Focus      []string `json:"focus"`
    36  	CorpusURLs []string `json:"corpus_urls"`
    37  	// Don't expect kernel coverage for the patched area.
    38  	SkipCoverCheck bool `json:"skip_cover_check"`
    39  	// Only report the bugs that match the regexp.
    40  	BugTitleRe string `json:"bug_title_re"`
    41  }
    42  
    43  // The triage step of the workflow will request these from controller.
    44  type Tree struct {
    45  	Name       string   `json:"name"` // Primary key.
    46  	URL        string   `json:"URL"`
    47  	Branch     string   `json:"branch"`
    48  	EmailLists []string `json:"email_lists"`
    49  }
    50  
    51  // KernelFuzzConfig is a specific fuzzing assignment.
    52  // Based on it, the triage step will construct FuzzTasks.
    53  type KernelFuzzConfig struct {
    54  	EmailLists     []string `json:"email_lists"`
    55  	Track          string   `json:"track"` // E.g. KASAN.
    56  	KernelConfig   string   `json:"kernel_config"`
    57  	Focus          string   `json:"focus"`
    58  	CorpusURL      string   `json:"corpus_url"`
    59  	SkipCoverCheck bool     `json:"skip_cover_check"`
    60  	BugTitleRe     string   `json:"bug_title_re"`
    61  }
    62  
    63  // FuzzTriageTarget is a single record in the list of supported fuzz configs.
    64  type FuzzTriageTarget struct {
    65  	EmailLists []string            `json:"email_lists"`
    66  	Campaigns  []*KernelFuzzConfig `json:"campaigns"`
    67  }
    68  
    69  type BuildRequest struct {
    70  	Arch       string `json:"arch"`
    71  	TreeName   string `json:"tree_name"`
    72  	TreeURL    string `json:"tree_url"`
    73  	CommitHash string `json:"commit_hash"`
    74  	ConfigName string `json:"config_name"` // These are known to both the triage and build steps.
    75  	SeriesID   string `json:"series_id"`
    76  }
    77  
    78  // BuildResult is returned from the build workflow step.
    79  type BuildResult struct {
    80  	BuildID string `json:"build_id"`
    81  	Success bool   `json:"success"`
    82  }
    83  
    84  type Build struct {
    85  	Arch         string    `json:"arch"`
    86  	TreeName     string    `json:"tree_name"`
    87  	TreeURL      string    `json:"tree_url"`
    88  	CommitHash   string    `json:"commit_hash"`
    89  	CommitDate   time.Time `json:"commit_date"`
    90  	ConfigName   string    `json:"config_name"`
    91  	SeriesID     string    `json:"series_id"`
    92  	Compiler     string    `json:"compiler"`
    93  	BuildSuccess bool      `json:"build_success"`
    94  }
    95  
    96  const (
    97  	TestRunning string = "running"
    98  	TestPassed  string = "passed"
    99  	TestSkipped string = "skipped"
   100  	TestFailed  string = "failed" // TODO: drop it? only mark completion?
   101  	TestError   string = "error"
   102  )
   103  
   104  type TestResult struct {
   105  	SessionID      string `json:"session_id"`
   106  	BaseBuildID    string `json:"base_build_id"`
   107  	PatchedBuildID string `json:"patched_build_id"`
   108  	TestName       string `json:"test_name"`
   109  	Result         string `json:"result"`
   110  	Log            []byte `json:"log"`
   111  }
   112  
   113  type BootResult struct {
   114  	Success bool `json:"success"`
   115  }
   116  
   117  // NewFinding is a kernel crash, boot error, etc. found during a test.
   118  type NewFinding struct {
   119  	SessionID    string `json:"session_id"`
   120  	TestName     string `json:"test_name"`
   121  	Title        string `json:"title"`
   122  	Report       []byte `json:"report"`
   123  	Log          []byte `json:"log"`
   124  	SyzRepro     []byte `json:"syz_repro"`
   125  	SyzReproOpts []byte `json:"syz_repro_opts"`
   126  	CRepro       []byte `json:"c_repro"`
   127  }
   128  
   129  type Series struct {
   130  	ID          string        `json:"id"` // Only included in the reply.
   131  	ExtID       string        `json:"ext_id"`
   132  	Title       string        `json:"title"`
   133  	AuthorEmail string        `json:"author_email"`
   134  	Cc          []string      `json:"cc"`
   135  	Version     int           `json:"version"`
   136  	Link        string        `json:"link"`
   137  	SubjectTags []string      `json:"subject_tags"`
   138  	PublishedAt time.Time     `json:"published_at"`
   139  	Patches     []SeriesPatch `json:"patches"`
   140  }
   141  
   142  func (s *Series) PatchBodies() [][]byte {
   143  	var ret [][]byte
   144  	for _, patch := range s.Patches {
   145  		ret = append(ret, patch.Body)
   146  	}
   147  	return ret
   148  }
   149  
   150  type SeriesPatch struct {
   151  	Seq   int    `json:"seq"`
   152  	Title string `json:"title"`
   153  	Link  string `json:"link"`
   154  	Body  []byte `json:"body"`
   155  }
   156  
   157  type NewSession struct {
   158  	ExtID string   `json:"ext_id"`
   159  	Tags  []string `json:"tags"`
   160  }
   161  
   162  type SessionReport struct {
   163  	ID         string     `json:"id"`
   164  	Moderation bool       `json:"moderation"`
   165  	Series     *Series    `json:"series"`
   166  	Findings   []*Finding `json:"findings"`
   167  	Link       string     `json:"link"` // URL to the web dashboard.
   168  }
   169  
   170  type Finding struct {
   171  	Title        string    `json:"title"`
   172  	Report       string    `json:"report"`
   173  	LogURL       string    `json:"log_url"`
   174  	Build        BuildInfo `json:"build"`
   175  	LinkCRepro   string    `json:"c_repro"`
   176  	LinkSyzRepro string    `json:"syz_repro"`
   177  	Invalidated  bool      `json:"invalidated"`
   178  }
   179  
   180  type BuildInfo struct {
   181  	TreeName   string `json:"tree_name"`
   182  	TreeURL    string `json:"tree_url"`
   183  	BaseCommit string `json:"base_commit"`
   184  	Arch       string `json:"arch"`
   185  	Compiler   string `json:"compiler"`
   186  	ConfigLink string `json:"config_link"`
   187  }
   188  
   189  // Let them stay here until we find a better place.
   190  // The list is ordered by decreasing importance.
   191  var DefaultTrees = []*Tree{
   192  	{
   193  		Name:       `bpf-next`,
   194  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next.git`,
   195  		Branch:     `master`,
   196  		EmailLists: []string{`bpf@vger.kernel.org`},
   197  	},
   198  	{
   199  		Name:       `bpf`,
   200  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf.git`,
   201  		Branch:     `master`,
   202  		EmailLists: []string{`bpf@vger.kernel.org`},
   203  	},
   204  	{
   205  		Name:       `nf-next`,
   206  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/netfilter/nf-next.git`,
   207  		Branch:     `main`,
   208  		EmailLists: []string{`netfilter-devel@vger.kernel.org`},
   209  	},
   210  	{
   211  		Name:       `nf`,
   212  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/netfilter/nf.git`,
   213  		Branch:     `main`,
   214  		EmailLists: []string{`netfilter-devel@vger.kernel.org`},
   215  	},
   216  	{
   217  		Name:       `net-next`,
   218  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/netdev/net-next.git`,
   219  		Branch:     `main`,
   220  		EmailLists: []string{`netdev@vger.kernel.org`},
   221  	},
   222  	{
   223  		Name:       `net`,
   224  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/netdev/net.git`,
   225  		Branch:     `main`,
   226  		EmailLists: []string{`netdev@vger.kernel.org`},
   227  	},
   228  	{
   229  		Name:       `kvm-next`,
   230  		URL:        `https://kernel.googlesource.com/pub/scm/virt/kvm/kvm/`,
   231  		Branch:     `next`,
   232  		EmailLists: []string{`kvm@vger.kernel.org`},
   233  	},
   234  	{
   235  		Name:       `drm-next`,
   236  		URL:        `https://gitlab.freedesktop.org/drm/kernel.git`,
   237  		Branch:     `drm-next`,
   238  		EmailLists: []string{`dri-devel@lists.freedesktop.org`},
   239  	},
   240  	{
   241  		Name:       `mm-new`,
   242  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/akpm/mm.git`,
   243  		Branch:     `mm-new`,
   244  		EmailLists: []string{`linux-mm@kvack.org`},
   245  	},
   246  	{
   247  		Name:       `torvalds`,
   248  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux`,
   249  		Branch:     `master`,
   250  		EmailLists: nil, // First fallback tree.
   251  	},
   252  	{
   253  		Name:       `linux-next`,
   254  		URL:        `https://kernel.googlesource.com/pub/scm/linux/kernel/git/next/linux-next`,
   255  		Branch:     `master`,
   256  		EmailLists: nil, // Second fallback tree. It's less stable, but more series can be applied.
   257  	},
   258  }
   259  
   260  const (
   261  	netCorpusURL = `https://storage.googleapis.com/syzkaller/corpus/ci-upstream-net-kasan-gce-corpus.db`
   262  	bpfCorpusURL = `https://storage.googleapis.com/syzkaller/corpus/ci-upstream-bpf-kasan-gce-corpus.db`
   263  	fsCorpusURL  = `https://storage.googleapis.com/syzkaller/corpus/ci2-upstream-fs-corpus.db`
   264  	allCorpusURL = `https://storage.googleapis.com/syzkaller/corpus/ci-upstream-kasan-gce-root-corpus.db`
   265  )
   266  
   267  const kasanTrack = "KASAN"
   268  
   269  // The list is ordered by decreasing importance.
   270  var FuzzTargets = []*FuzzTriageTarget{
   271  	{
   272  		EmailLists: []string{`kvm@vger.kernel.org`},
   273  		Campaigns: []*KernelFuzzConfig{
   274  			{
   275  				Track:        kasanTrack,
   276  				KernelConfig: `upstream-apparmor-kasan.config`,
   277  				Focus:        FocusKVM,
   278  				CorpusURL:    allCorpusURL,
   279  			},
   280  		},
   281  	},
   282  	{
   283  		EmailLists: []string{`io-uring@vger.kernel.org`},
   284  		Campaigns: []*KernelFuzzConfig{
   285  			{
   286  				Track:        kasanTrack,
   287  				KernelConfig: `upstream-apparmor-kasan.config`,
   288  				Focus:        FocusIoUring,
   289  				CorpusURL:    allCorpusURL,
   290  			},
   291  		},
   292  	},
   293  	{
   294  		EmailLists: []string{`bpf@vger.kernel.org`},
   295  		Campaigns: []*KernelFuzzConfig{
   296  			{
   297  				Track:        kasanTrack,
   298  				KernelConfig: `upstream-apparmor-kasan.config`,
   299  				Focus:        FocusBPF,
   300  				CorpusURL:    bpfCorpusURL,
   301  			},
   302  		},
   303  	},
   304  	{
   305  		EmailLists: []string{
   306  			`netdev@vger.kernel.org`,
   307  			`netfilter-devel@vger.kernel.org`,
   308  			`linux-wireless@vger.kernel.org`,
   309  		},
   310  		Campaigns: []*KernelFuzzConfig{
   311  			{
   312  				Track:        kasanTrack,
   313  				KernelConfig: `upstream-apparmor-kasan.config`,
   314  				Focus:        FocusNet,
   315  				CorpusURL:    netCorpusURL,
   316  			},
   317  		},
   318  	},
   319  	{
   320  		EmailLists: []string{
   321  			`linux-fsdevel@vger.kernel.org`,
   322  			`linux-block@vger.kernel.org`,
   323  			`linux-unionfs@vger.kernel.org`,
   324  			`linux-ext4@vger.kernel.org`,
   325  		},
   326  		Campaigns: []*KernelFuzzConfig{
   327  			{
   328  				KernelConfig: `upstream-apparmor-kasan.config`,
   329  				Track:        kasanTrack,
   330  				Focus:        FocusFS,
   331  				CorpusURL:    fsCorpusURL,
   332  			},
   333  		},
   334  	},
   335  	{
   336  		EmailLists: []string{`linux-mm@kvack.org`},
   337  		Campaigns: []*KernelFuzzConfig{
   338  			{
   339  				KernelConfig: `upstream-apparmor-kasan.config`,
   340  				Track:        kasanTrack,
   341  				CorpusURL:    allCorpusURL,
   342  				// Not all mm/ code is instrumented with KCOV.
   343  				SkipCoverCheck: true,
   344  			},
   345  		},
   346  	},
   347  	{
   348  		EmailLists: nil, // A fallback option.
   349  		Campaigns: []*KernelFuzzConfig{
   350  			{
   351  				KernelConfig: `upstream-apparmor-kasan.config`,
   352  				Track:        kasanTrack,
   353  				CorpusURL:    allCorpusURL,
   354  			},
   355  		},
   356  	},
   357  }