diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-12-18 10:24:59 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-12-18 10:33:05 +0100 |
| commit | bd8b4220d51d391adeba08cfcd2c886b9f0b0599 (patch) | |
| tree | 497d79b6b748549ab2dd50a3c13b581748ddf5f4 | |
| parent | 71b3a323ebdd4dfe9f32424d0ef9dd39f5086ad0 (diff) | |
syz-ci: upload syzkaller build errors to dashboard
Fixes #793
| -rw-r--r-- | syz-ci/manager.go | 19 | ||||
| -rw-r--r-- | syz-ci/syz-ci.go | 13 | ||||
| -rw-r--r-- | syz-ci/syzupdater.go | 124 | ||||
| -rw-r--r-- | syz-ci/testdata/example.cfg | 10 |
4 files changed, 106 insertions, 60 deletions
diff --git a/syz-ci/manager.go b/syz-ci/manager.go index 7cd5b7adc..68dd7636d 100644 --- a/syz-ci/manager.go +++ b/syz-ci/manager.go @@ -107,27 +107,14 @@ func createManager(cfg *Config, mgrcfg *ManagerConfig, stop chan struct{}) *Mana if syzkallerCommit == "" { log.Fatalf("no tag in syzkaller/current/tag") } - - // Prepare manager config skeleton (other fields are filled in writeConfig). - managercfg, err := mgrconfig.LoadPartialData(mgrcfg.ManagerConfig) - if err != nil { - log.Fatalf("failed to load manager %v config: %v", mgrcfg.Name, err) - } - managercfg.Name = cfg.Name + "-" + mgrcfg.Name - managercfg.Syzkaller = filepath.FromSlash("syzkaller/current") - if managercfg.HTTP == "" { - managercfg.HTTP = fmt.Sprintf(":%v", cfg.ManagerPort) - cfg.ManagerPort++ - } - kernelDir := filepath.Join(dir, "kernel") - repo, err := vcs.NewRepo(managercfg.TargetOS, managercfg.Type, kernelDir) + repo, err := vcs.NewRepo(mgrcfg.managercfg.TargetOS, mgrcfg.managercfg.Type, kernelDir) if err != nil { log.Fatalf("failed to create repo for %v: %v", mgrcfg.Name, err) } mgr := &Manager{ - name: managercfg.Name, + name: mgrcfg.managercfg.Name, workDir: filepath.Join(dir, "workdir"), kernelDir: kernelDir, currentDir: filepath.Join(dir, "current"), @@ -139,7 +126,7 @@ func createManager(cfg *Config, mgrcfg *ManagerConfig, stop chan struct{}) *Mana cfg: cfg, repo: repo, mgrcfg: mgrcfg, - managercfg: managercfg, + managercfg: mgrcfg.managercfg, dash: dash, stop: stop, } diff --git a/syz-ci/syz-ci.go b/syz-ci/syz-ci.go index 4489a9896..738b9d599 100644 --- a/syz-ci/syz-ci.go +++ b/syz-ci/syz-ci.go @@ -60,6 +60,7 @@ import ( "net/http" _ "net/http/pprof" "os" + "path/filepath" "sync" "github.com/google/syzkaller/pkg/config" @@ -108,6 +109,7 @@ type ManagerConfig struct { // File with sysctl values (e.g. output of sysctl -a, optional). KernelSysctl string `json:"kernel_sysctl"` ManagerConfig json.RawMessage `json:"manager_config"` + managercfg *mgrconfig.Config } func main() { @@ -223,10 +225,17 @@ func loadConfig(filename string) (*Config, error) { if mgr.Branch == "" { mgr.Branch = "master" } - mgrcfg := new(mgrconfig.Config) - if err := config.LoadData(mgr.ManagerConfig, mgrcfg); err != nil { + managercfg, err := mgrconfig.LoadPartialData(mgr.ManagerConfig) + if err != nil { return nil, fmt.Errorf("manager %v: %v", mgr.Name, err) } + mgr.managercfg = managercfg + managercfg.Name = cfg.Name + "-" + mgr.Name + managercfg.Syzkaller = filepath.FromSlash("syzkaller/current") + if managercfg.HTTP == "" { + managercfg.HTTP = fmt.Sprintf(":%v", cfg.ManagerPort) + cfg.ManagerPort++ + } } return cfg, nil } diff --git a/syz-ci/syzupdater.go b/syz-ci/syzupdater.go index ee4f86140..c86a678d3 100644 --- a/syz-ci/syzupdater.go +++ b/syz-ci/syzupdater.go @@ -12,9 +12,9 @@ import ( "syscall" "time" + "github.com/google/syzkaller/dashboard/dashapi" "github.com/google/syzkaller/pkg/instance" "github.com/google/syzkaller/pkg/log" - "github.com/google/syzkaller/pkg/mgrconfig" "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/pkg/vcs" ) @@ -31,17 +31,20 @@ const ( // Additionally it updates and restarts the current executable as necessary. // Current executable is always built on the same revision as the rest of syzkaller binaries. type SyzUpdater struct { - repo vcs.Repo - exe string - repoAddress string - branch string - descriptions string - gopathDir string - syzkallerDir string - latestDir string - currentDir string - syzFiles map[string]bool - targets map[string]bool + repo vcs.Repo + exe string + repoAddress string + branch string + descriptions string + gopathDir string + syzkallerDir string + latestDir string + currentDir string + syzFiles map[string]bool + targets map[string]bool + dashboardAddr string + compilerID string + mgrcfg *ManagerConfig } func NewSyzUpdater(cfg *Config) *SyzUpdater { @@ -77,10 +80,7 @@ func NewSyzUpdater(cfg *Config) *SyzUpdater { } targets := make(map[string]bool) for _, mgr := range cfg.Managers { - mgrcfg, err := mgrconfig.LoadPartialData(mgr.ManagerConfig) - if err != nil { - log.Fatalf("failed to load manager %v config: %v", mgr.Name, err) - } + mgrcfg := mgr.managercfg os, vmarch, arch := mgrcfg.TargetOS, mgrcfg.TargetVMArch, mgrcfg.TargetArch targets[os+"/"+vmarch+"/"+arch] = true files[fmt.Sprintf("bin/%v_%v/syz-fuzzer", os, vmarch)] = true @@ -91,18 +91,25 @@ func NewSyzUpdater(cfg *Config) *SyzUpdater { for f := range files { syzFiles[f] = true } + compilerID, err := osutil.RunCmd(time.Minute, "", "go", "version") + if err != nil { + log.Fatalf("%v", exe) + } return &SyzUpdater{ - repo: vcs.NewSyzkallerRepo(syzkallerDir), - exe: exe, - repoAddress: cfg.SyzkallerRepo, - branch: cfg.SyzkallerBranch, - descriptions: cfg.SyzkallerDescriptions, - gopathDir: gopath, - syzkallerDir: syzkallerDir, - latestDir: filepath.Join("syzkaller", "latest"), - currentDir: filepath.Join("syzkaller", "current"), - syzFiles: syzFiles, - targets: targets, + repo: vcs.NewSyzkallerRepo(syzkallerDir), + exe: exe, + repoAddress: cfg.SyzkallerRepo, + branch: cfg.SyzkallerBranch, + descriptions: cfg.SyzkallerDescriptions, + gopathDir: gopath, + syzkallerDir: syzkallerDir, + latestDir: filepath.Join("syzkaller", "latest"), + currentDir: filepath.Join("syzkaller", "current"), + syzFiles: syzFiles, + targets: targets, + dashboardAddr: cfg.DashboardAddr, + compilerID: strings.TrimSpace(string(compilerID)), + mgrcfg: cfg.Managers[0], } } @@ -202,6 +209,7 @@ func (upd *SyzUpdater) pollAndBuild(lastCommit string) string { lastCommit = commit.Hash if err := upd.build(commit); err != nil { log.Logf(0, "syzkaller: %v", err) + upd.uploadBuildError(commit, err) } } return lastCommit @@ -220,18 +228,18 @@ func (upd *SyzUpdater) build(commit *vcs.Commit) error { return err } } + cmd := osutil.Command(instance.MakeBin, "generate") + cmd.Dir = upd.syzkallerDir + cmd.Env = append([]string{"GOPATH=" + upd.gopathDir}, os.Environ()...) + if _, err := osutil.Run(time.Hour, cmd); err != nil { + return osutil.PrependContext("generate failed", err) + } } - cmd := osutil.Command(instance.MakeBin, "generate") - cmd.Dir = upd.syzkallerDir - cmd.Env = append([]string{"GOPATH=" + upd.gopathDir}, os.Environ()...) - if _, err := osutil.Run(time.Hour, cmd); err != nil { - return fmt.Errorf("build failed: %v", err) - } - cmd = osutil.Command(instance.MakeBin, "host", "ci") + cmd := osutil.Command(instance.MakeBin, "host", "ci") cmd.Dir = upd.syzkallerDir cmd.Env = append([]string{"GOPATH=" + upd.gopathDir}, os.Environ()...) if _, err := osutil.Run(time.Hour, cmd); err != nil { - return fmt.Errorf("build failed: %v", err) + return osutil.PrependContext("make host failed", err) } for target := range upd.targets { parts := strings.Split(target, "/") @@ -245,14 +253,14 @@ func (upd *SyzUpdater) build(commit *vcs.Commit) error { "TARGETARCH="+parts[2], ) if _, err := osutil.Run(time.Hour, cmd); err != nil { - return fmt.Errorf("build failed: %v", err) + return osutil.PrependContext("make target failed", err) } } cmd = osutil.Command("go", "test", "-short", "./...") cmd.Dir = upd.syzkallerDir cmd.Env = append([]string{"GOPATH=" + upd.gopathDir}, os.Environ()...) if _, err := osutil.Run(time.Hour, cmd); err != nil { - return fmt.Errorf("tests failed: %v", err) + return osutil.PrependContext("testing failed: %v", err) } tagFile := filepath.Join(upd.syzkallerDir, "tag") if err := osutil.WriteFile(tagFile, []byte(commit.Hash)); err != nil { @@ -264,6 +272,48 @@ func (upd *SyzUpdater) build(commit *vcs.Commit) error { return nil } +func (upd *SyzUpdater) uploadBuildError(commit *vcs.Commit, buildErr error) { + // Build errors can't be uploaded using global client + // as it is not associated with any namespace. + // So we use the first manager client for this. + if upd.dashboardAddr == "" || upd.mgrcfg.DashboardClient == "" { + return + } + dash := dashapi.New(upd.dashboardAddr, upd.mgrcfg.DashboardClient, upd.mgrcfg.DashboardKey) + var title string + var output []byte + if verbose, ok := buildErr.(*osutil.VerboseError); ok { + title = verbose.Title + output = verbose.Output + } else { + title = buildErr.Error() + } + title = "syzkaller: " + title + managercfg := upd.mgrcfg.managercfg + req := &dashapi.BuildErrorReq{ + Build: dashapi.Build{ + Manager: managercfg.Name, + ID: commit.Hash, + OS: managercfg.TargetOS, + Arch: managercfg.TargetArch, + VMArch: managercfg.TargetVMArch, + SyzkallerCommit: commit.Hash, + CompilerID: upd.compilerID, + KernelRepo: upd.repoAddress, + KernelBranch: upd.branch, + KernelCommit: commit.Hash, + KernelCommitTitle: commit.Title, + KernelCommitDate: commit.Date, + }, + Crash: dashapi.Crash{ + Title: title, + Log: output, + }, + } + // TODO: log ReportBuildError error to dashboard. + dash.ReportBuildError(req) +} + // checkLatest returns tag of the latest build, // or an empty string if latest build is missing/broken. func (upd *SyzUpdater) checkLatest() string { diff --git a/syz-ci/testdata/example.cfg b/syz-ci/testdata/example.cfg index 413c35095..9406fa5c3 100644 --- a/syz-ci/testdata/example.cfg +++ b/syz-ci/testdata/example.cfg @@ -16,10 +16,10 @@ "userspace": "/syzkaller/wheezy", "kernel_config": "/syzkaller/kasan.config", "manager_config": { - "http": ":10000", - "type": "gce", + "target": "linux/amd64", "sandbox": "namespace", "procs": 8, + "type": "gce", "vm": { "count": 10, "machine_type": "n1-standard-2", @@ -35,10 +35,10 @@ "userspace": "/syzkaller/wheezy", "kernel_config": "/syzkaller/kasan.config", "manager_config": { - "http": ":10001", - "type": "gce", - "sandbox": "namespace", + "target": "linux/amd64", + "sandbox": "none", "procs": 8, + "type": "gce", "vm": { "count": 10, "machine_type": "n1-standard-2", |
