diff options
| author | Space Meyer <meyerpatrick@google.com> | 2022-07-30 12:16:05 +0000 |
|---|---|---|
| committer | Aleksandr Nogikh <wp32pw@gmail.com> | 2022-09-01 10:42:40 +0200 |
| commit | d8e6f911090ec0020f34e094005284b5c8ac1e7f (patch) | |
| tree | a66996629b5aa75ac0a06a58af547dafa73f94a7 | |
| parent | 3f79a9101d6ae91acf7edde3727992988bb01ae1 (diff) | |
pkg/bisect: support clang for crash bisection
Before we hardcoded bisection to use gcc, now the compiler family can
be configured in the bisection config.
| -rw-r--r-- | pkg/bisect/bisect.go | 25 | ||||
| -rw-r--r-- | pkg/vcs/linux.go | 80 | ||||
| -rw-r--r-- | pkg/vcs/testos.go | 4 | ||||
| -rw-r--r-- | pkg/vcs/vcs.go | 4 | ||||
| -rw-r--r-- | syz-ci/jobs.go | 9 | ||||
| -rw-r--r-- | syz-ci/syz-ci.go | 29 | ||||
| -rw-r--r-- | tools/syz-bisect/bisect.go | 13 | ||||
| -rw-r--r-- | tools/syz-testbuild/testbuild.go | 4 |
8 files changed, 107 insertions, 61 deletions
diff --git a/pkg/bisect/bisect.go b/pkg/bisect/bisect.go index 0948bc653..1813abaa5 100644 --- a/pkg/bisect/bisect.go +++ b/pkg/bisect/bisect.go @@ -19,15 +19,16 @@ import ( ) type Config struct { - Trace debugtracer.DebugTracer - Fix bool - BinDir string - Ccache string - Timeout time.Duration - Kernel KernelConfig - Syzkaller SyzkallerConfig - Repro ReproConfig - Manager *mgrconfig.Config + Trace debugtracer.DebugTracer + Fix bool + BisectCompiler string + BinDir string + Ccache string + Timeout time.Duration + Kernel KernelConfig + Syzkaller SyzkallerConfig + Repro ReproConfig + Manager *mgrconfig.Config } type KernelConfig struct { @@ -375,7 +376,7 @@ func (env *env) commitRangeForFix() (*vcs.Commit, *vcs.Commit, *report.Report, [ func (env *env) commitRangeForBug() (*vcs.Commit, *vcs.Commit, *report.Report, []*testResult, error) { cfg := env.cfg - tags, err := env.bisecter.PreviousReleaseTags(cfg.Kernel.Commit) + tags, err := env.bisecter.PreviousReleaseTags(cfg.Kernel.Commit, cfg.BisectCompiler) if err != nil { return nil, nil, nil, nil, err } @@ -420,11 +421,11 @@ func (env *env) build() (*vcs.Commit, string, error) { return nil, "", err } - bisectEnv, err := env.bisecter.EnvForCommit(env.cfg.BinDir, current.Hash, env.kernelConfig) + bisectEnv, err := env.bisecter.EnvForCommit(env.cfg.BisectCompiler, env.cfg.BinDir, current.Hash, env.kernelConfig) if err != nil { return current, "", err } - env.log("testing commit %v", current.Hash) + env.log("testing commit %v %v", current.Hash, env.cfg.BisectCompiler) buildStart := time.Now() mgr := env.cfg.Manager if err := build.Clean(mgr.TargetOS, mgr.TargetVMArch, mgr.Type, mgr.KernelSrc); err != nil { diff --git a/pkg/vcs/linux.go b/pkg/vcs/linux.go index d2371ca5c..8ee801430 100644 --- a/pkg/vcs/linux.go +++ b/pkg/vcs/linux.go @@ -42,32 +42,43 @@ func newLinux(dir string, opts []RepoOpt, vmType string) *linux { } } -func (ctx *linux) PreviousReleaseTags(commit string) ([]string, error) { +func (ctx *linux) PreviousReleaseTags(commit, bisectCompiler string) ([]string, error) { tags, err := ctx.git.previousReleaseTags(commit, false, false, false) if err != nil { return nil, err } + + cutoff := "" + if bisectCompiler == "gcc" { + // Initially we tried to stop at 3.8 because: + // v3.8 does not work with modern perl, and as we go further in history + // make stops to work, then binutils, glibc, etc. So we stop at v3.8. + // Up to that point we only need an ancient gcc. + // + // But kernels don't boot starting from 4.0 and back. + // That was fixed by 99124e4db5b7b70daeaaf1d88a6a8078a0004c6e, + // and it can be cherry-picked into 3.14..4.0 but it conflicts for 3.13 and older. + // + // But starting from 4.0 our user-space binaries start crashing with + // assorted errors which suggests process memory corruption by kernel. + // + // We used to use 4.1 as the oldest tested release (it works in general). + // However, there is correlation between how far back we go and probability + // of getting correct result (see #1532). So we now stop at 4.6. + // 4.6 is somewhat arbitrary, we've seen lots of wrong results in 4.5..4.6 range, + // but there is definitive reason for 4.6. Most likely later we want to bump it + // even more (as new releases are produced). Next good candidate may be 4.11 + // because then we won't need gcc 5.5. + cutoff = "v4.5" + } else if bisectCompiler == "clang" { + // v5.3 was the first release with solid clang support, however I was able to + // compile v5.1..v5.3 using a newer defconfig + make oldconfig. Everything older + // would require further cherry-picks. + cutoff = "v5.2" + } + for i, tag := range tags { - if tag == "v4.5" { - // Initially we tried to stop at 3.8 because: - // v3.8 does not work with modern perl, and as we go further in history - // make stops to work, then binutils, glibc, etc. So we stop at v3.8. - // Up to that point we only need an ancient gcc. - // - // But kernels don't boot starting from 4.0 and back. - // That was fixed by 99124e4db5b7b70daeaaf1d88a6a8078a0004c6e, - // and it can be cherry-picked into 3.14..4.0 but it conflicts for 3.13 and older. - // - // But starting from 4.0 our user-space binaries start crashing with - // assorted errors which suggests process memory corruption by kernel. - // - // We used to use 4.1 as the oldest tested release (it works in general). - // However, there is correlation between how far back we go and probability - // of getting correct result (see #1532). So we now stop at 4.6. - // 4.6 is somewhat arbitrary, we've seen lots of wrong results in 4.5..4.6 range, - // but there is definitive reason for 4.6. Most likely later we want to bump it - // even more (as new releases are produced). Next good candidate may be 4.11 - // because then we won't need gcc 5.5. + if tag == cutoff { tags = tags[:i] break } @@ -121,7 +132,7 @@ func gitReleaseTagToInt(tag string, includeRC bool) uint64 { return v1*1e9 + v2*1e6 + rc*1e3 + v3 } -func (ctx *linux) EnvForCommit(binDir, commit string, kernelConfig []byte) (*BisectEnv, error) { +func (ctx *linux) EnvForCommit(bisectCompiler, binDir, commit string, kernelConfig []byte) (*BisectEnv, error) { tagList, err := ctx.previousReleaseTags(commit, true, false, false) if err != nil { return nil, err @@ -135,8 +146,18 @@ func (ctx *linux) EnvForCommit(binDir, commit string, kernelConfig []byte) (*Bis return nil, err } linuxAlterConfigs(cf, tags) + + compiler := "" + if bisectCompiler == "gcc" { + compiler = filepath.Join(binDir, "gcc-"+linuxGCCVersion(tags), "bin", "gcc") + } else if bisectCompiler == "clang" { + compiler = filepath.Join(binDir, "llvm-"+linuxClangVersion(tags), "bin", "clang") + } else { + return nil, fmt.Errorf("unsupported bisect compiler: %v", bisectCompiler) + } + env := &BisectEnv{ - Compiler: filepath.Join(binDir, "gcc-"+linuxCompilerVersion(tags), "bin", "gcc"), + Compiler: compiler, KernelConfig: cf.Serialize(), } @@ -159,7 +180,18 @@ func (ctx *linux) EnvForCommit(binDir, commit string, kernelConfig []byte) (*Bis return env, nil } -func linuxCompilerVersion(tags map[string]bool) string { +func linuxClangVersion(tags map[string]bool) string { + switch { + case tags["v5.9"]: + return "14.0.6" + default: + // everything before v5.3 might not work great + // everything before v5.1 does not work + return "9.0.1" + } +} + +func linuxGCCVersion(tags map[string]bool) string { switch { case tags["v5.9"]: return "10.1.0" diff --git a/pkg/vcs/testos.go b/pkg/vcs/testos.go index baadb1a2a..0053a528e 100644 --- a/pkg/vcs/testos.go +++ b/pkg/vcs/testos.go @@ -22,11 +22,11 @@ func newTestos(dir string, opts []RepoOpt) *testos { } } -func (ctx *testos) PreviousReleaseTags(commit string) ([]string, error) { +func (ctx *testos) PreviousReleaseTags(commit, bisectCompiler string) ([]string, error) { return ctx.git.previousReleaseTags(commit, false, false, false) } -func (ctx *testos) EnvForCommit(binDir, commit string, kernelConfig []byte) (*BisectEnv, error) { +func (ctx *testos) EnvForCommit(bisectCompiler, binDir, commit string, kernelConfig []byte) (*BisectEnv, error) { return &BisectEnv{KernelConfig: kernelConfig}, nil } diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index ae7bc8508..4e42b04a0 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -78,11 +78,11 @@ type Bisecter interface { // PreviousReleaseTags returns list of preceding release tags that are reachable from the given commit. // If the commit itself has a release tag, this tag is not included. - PreviousReleaseTags(commit string) ([]string, error) + PreviousReleaseTags(commit, bisectCompiler string) ([]string, error) IsRelease(commit string) (bool, error) - EnvForCommit(binDir, commit string, kernelConfig []byte) (*BisectEnv, error) + EnvForCommit(bisectCompiler, binDir, commit string, kernelConfig []byte) (*BisectEnv, error) } type ConfigMinimizer interface { diff --git a/syz-ci/jobs.go b/syz-ci/jobs.go index c77cb3f26..5a4addb02 100644 --- a/syz-ci/jobs.go +++ b/syz-ci/jobs.go @@ -412,10 +412,11 @@ func (jp *JobProcessor) bisect(job *Job, mgrcfg *mgrconfig.Config) error { // compete with patch testing jobs (it's bad delaying patch testing). // When/if bisection jobs don't compete with patch testing, // it makes sense to increase this to 12-24h. - Timeout: 8 * time.Hour, - Fix: req.Type == dashapi.JobBisectFix, - BinDir: jp.cfg.BisectBinDir, - Ccache: jp.cfg.Ccache, + Timeout: 8 * time.Hour, + Fix: req.Type == dashapi.JobBisectFix, + BisectCompiler: mgr.mgrcfg.BisectCompiler, + BinDir: jp.cfg.BisectBinDir, + Ccache: jp.cfg.Ccache, Kernel: bisect.KernelConfig{ Repo: mgr.mgrcfg.Repo, Branch: mgr.mgrcfg.Branch, diff --git a/syz-ci/syz-ci.go b/syz-ci/syz-ci.go index 54d9b877c..944c0c745 100644 --- a/syz-ci/syz-ci.go +++ b/syz-ci/syz-ci.go @@ -102,10 +102,13 @@ type Config struct { CoverUploadPath string `json:"cover_upload_path"` // Path to upload corpus.db from managers (optional). // Supported protocols: GCS (gs://) and HTTP PUT (http:// or https://). - CorpusUploadPath string `json:"corpus_upload_path"` - BisectBinDir string `json:"bisect_bin_dir"` - Ccache string `json:"ccache"` - Managers []*ManagerConfig `json:"managers"` + CorpusUploadPath string `json:"corpus_upload_path"` + // BinDir must point to a dir that contains compilers required to build + // older versions of the kernel. For linux, it needs to include several + // compiler versions. + BisectBinDir string `json:"bisect_bin_dir"` + Ccache string `json:"ccache"` + Managers []*ManagerConfig `json:"managers"` // Poll period for jobs in seconds (optional, defaults to 10 seconds) JobPollPeriod int `json:"job_poll_period"` // Poll period for commits in seconds (optional, defaults to 3600 seconds) @@ -149,12 +152,15 @@ type ManagerConfig struct { DashboardKey string `json:"dashboard_key"` Repo string `json:"repo"` // Short name of the repo (e.g. "linux-next"), used only for reporting. - RepoAlias string `json:"repo_alias"` - Branch string `json:"branch"` // Defaults to "master". - Compiler string `json:"compiler"` - Ccache string `json:"ccache"` - Userspace string `json:"userspace"` - KernelConfig string `json:"kernel_config"` + RepoAlias string `json:"repo_alias"` + // Currently either 'gcc' or 'clang'. Note that pkg/bisect requires + // explicit plumbing for every os/compiler combination. + BisectCompiler string `json:"bisect_compiler"` // Defaults to "gcc" + Branch string `json:"branch"` // Defaults to "master". + Compiler string `json:"compiler"` + Ccache string `json:"ccache"` + Userspace string `json:"userspace"` + KernelConfig string `json:"kernel_config"` // Baseline config for bisection, see pkg/bisect.KernelConfig.BaselineConfig. KernelBaselineConfig string `json:"kernel_baseline_config"` // File with kernel cmdline values (optional). @@ -380,6 +386,9 @@ func loadManagerConfig(cfg *Config, mgr *ManagerConfig) error { if !managerNameRe.MatchString(mgr.Name) { return fmt.Errorf("param 'managers.name' has bad value: %q", mgr.Name) } + if mgr.BisectCompiler == "" { + mgr.BisectCompiler = "gcc" + } if mgr.Branch == "" { mgr.Branch = "master" } diff --git a/tools/syz-bisect/bisect.go b/tools/syz-bisect/bisect.go index 1c8692700..9712ddcd3 100644 --- a/tools/syz-bisect/bisect.go +++ b/tools/syz-bisect/bisect.go @@ -43,10 +43,12 @@ var ( ) type Config struct { + // Currently either 'gcc' or 'clang'. Note that pkg/bisect requires + // explicit plumbing for every os/compiler combination. + BisectCompiler string `json:"bisect_compiler"` // BinDir must point to a dir that contains compilers required to build // older versions of the kernel. For linux, it needs to include several - // gcc versions. A working archive can be downloaded from: - // https://storage.googleapis.com/syzkaller/bisect_bin.tar.gz + // compiler versions. BinDir string `json:"bin_dir"` Ccache string `json:"ccache"` KernelRepo string `json:"kernel_repo"` @@ -94,9 +96,10 @@ func main() { TraceWriter: os.Stdout, OutDir: *flagCrash, }, - Fix: *flagFix, - BinDir: mycfg.BinDir, - Ccache: mycfg.Ccache, + Fix: *flagFix, + BisectCompiler: mycfg.BisectCompiler, + BinDir: mycfg.BinDir, + Ccache: mycfg.Ccache, Kernel: bisect.KernelConfig{ Repo: mycfg.KernelRepo, Branch: mycfg.KernelBranch, diff --git a/tools/syz-testbuild/testbuild.go b/tools/syz-testbuild/testbuild.go index 9fe1dd3f1..be2718b3a 100644 --- a/tools/syz-testbuild/testbuild.go +++ b/tools/syz-testbuild/testbuild.go @@ -101,7 +101,7 @@ func main() { tool.Fail(err) } log.Printf("HEAD is on %v %v", head.Hash, head.Title) - tags, err := bisecter.PreviousReleaseTags(head.Hash) + tags, err := bisecter.PreviousReleaseTags(head.Hash, "gcc") if err != nil { tool.Fail(err) } @@ -125,7 +125,7 @@ func main() { } func test(repo vcs.Repo, bisecter vcs.Bisecter, kernelConfig []byte, env instance.Env, com *vcs.Commit) { - bisectEnv, err := bisecter.EnvForCommit(*flagBisectBin, com.Hash, kernelConfig) + bisectEnv, err := bisecter.EnvForCommit("gcc", *flagBisectBin, com.Hash, kernelConfig) if err != nil { tool.Fail(err) } |
