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

     1  // Copyright 2025 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 triage
     5  
     6  import (
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/google/syzkaller/syz-cluster/pkg/api"
    11  )
    12  
    13  func SelectFuzzConfigs(series *api.Series, fuzzConfigs []*api.FuzzTriageTarget) []*api.KernelFuzzConfig {
    14  	seriesCc := map[string]bool{}
    15  	for _, cc := range series.Cc {
    16  		seriesCc[strings.ToLower(cc)] = true
    17  	}
    18  	var ret, defaultRet []*api.KernelFuzzConfig
    19  	for _, config := range fuzzConfigs {
    20  		intersects := false
    21  		for _, cc := range config.EmailLists {
    22  			intersects = intersects || seriesCc[cc]
    23  		}
    24  		if intersects {
    25  			ret = append(ret, config.Campaigns...)
    26  		} else if len(config.EmailLists) == 0 {
    27  			defaultRet = append(defaultRet, config.Campaigns...)
    28  		}
    29  	}
    30  	// We want to return the fallback option only if no element matched exactly.
    31  	if len(ret) > 0 {
    32  		return ret
    33  	}
    34  	return defaultRet
    35  }
    36  
    37  type MergedFuzzConfig struct {
    38  	KernelConfig string
    39  	FuzzConfig   *api.FuzzConfig
    40  }
    41  
    42  func MergeKernelFuzzConfigs(configs []*api.KernelFuzzConfig) []*MergedFuzzConfig {
    43  	type groupKey struct {
    44  		config     string
    45  		track      string
    46  		bugTitleRe string
    47  	}
    48  	groups := map[groupKey][]*api.KernelFuzzConfig{}
    49  	var orderedKeys []groupKey
    50  	for _, config := range configs {
    51  		// Some of the different fuzz configs may still be merged together,
    52  		// e.g. if they only differ in the syscall lists and corpuses.
    53  		key := groupKey{config.KernelConfig, config.Track, config.BugTitleRe}
    54  		if _, ok := groups[key]; !ok {
    55  			orderedKeys = append(orderedKeys, key)
    56  		}
    57  		groups[key] = append(groups[key], config)
    58  	}
    59  	var ret []*MergedFuzzConfig
    60  	for _, key := range orderedKeys {
    61  		// TODO: is there way to auto-generate a prefix?
    62  		ret = append(ret, &MergedFuzzConfig{
    63  			KernelConfig: key.config,
    64  			FuzzConfig:   mergeFuzzConfigs(groups[key]),
    65  		})
    66  	}
    67  	return ret
    68  }
    69  
    70  func mergeFuzzConfigs(configs []*api.KernelFuzzConfig) *api.FuzzConfig {
    71  	var ret api.FuzzConfig
    72  	for _, config := range configs {
    73  		if config.Focus != "" {
    74  			ret.Focus = append(ret.Focus, config.Focus)
    75  		}
    76  		if config.CorpusURL != "" {
    77  			ret.CorpusURLs = append(ret.CorpusURLs, config.CorpusURL)
    78  		}
    79  		ret.SkipCoverCheck = ret.SkipCoverCheck || config.SkipCoverCheck
    80  		// Must be the same.
    81  		ret.BugTitleRe = config.BugTitleRe
    82  		ret.Track = config.Track
    83  	}
    84  	ret.Focus = unique(ret.Focus)
    85  	ret.CorpusURLs = unique(ret.CorpusURLs)
    86  	return &ret
    87  }
    88  
    89  func unique(list []string) []string {
    90  	seen := make(map[string]struct{}, len(list))
    91  	for _, s := range list {
    92  		seen[s] = struct{}{}
    93  	}
    94  	var unique []string
    95  	for s := range seen {
    96  		unique = append(unique, s)
    97  	}
    98  	sort.Strings(unique)
    99  	return unique
   100  }