aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-12-18 10:24:59 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-12-18 10:33:05 +0100
commitbd8b4220d51d391adeba08cfcd2c886b9f0b0599 (patch)
tree497d79b6b748549ab2dd50a3c13b581748ddf5f4
parent71b3a323ebdd4dfe9f32424d0ef9dd39f5086ad0 (diff)
syz-ci: upload syzkaller build errors to dashboard
Fixes #793
-rw-r--r--syz-ci/manager.go19
-rw-r--r--syz-ci/syz-ci.go13
-rw-r--r--syz-ci/syzupdater.go124
-rw-r--r--syz-ci/testdata/example.cfg10
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",