aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2025-01-21 11:44:27 +0100
committerAleksandr Nogikh <nogikh@google.com>2025-01-21 15:46:02 +0000
commitcce8ebd1002f4970df17ee9a7d9694a0a07fa965 (patch)
tree07857e8b826c1ace00a478b1cf83162a1419a55d
parent6e87cfa299c98d36e79e8b8718a4126899a3ba2f (diff)
pkg/instance: extract the smoke test method
Move the logic from syz-ci to pkg/instance to make it reusable. In case of a failure without a crash report, report the issue as a SYZFATAL crash instead of just printing to the error log.
-rw-r--r--pkg/instance/instance.go39
-rw-r--r--syz-ci/manager.go69
2 files changed, 54 insertions, 54 deletions
diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go
index 411568e65..83a855e36 100644
--- a/pkg/instance/instance.go
+++ b/pkg/instance/instance.go
@@ -16,6 +16,7 @@ import (
"time"
"github.com/google/syzkaller/pkg/build"
+ "github.com/google/syzkaller/pkg/config"
"github.com/google/syzkaller/pkg/csource"
"github.com/google/syzkaller/pkg/log"
"github.com/google/syzkaller/pkg/mgrconfig"
@@ -537,3 +538,41 @@ func (s *Semaphore) Signal() {
}
s.ch <- struct{}{}
}
+
+// RunSmokeTest executes syz-manager in the smoke test mode and returns two values:
+// The crash report, if the testing failed.
+// An error if there was a problem not related to testing the kernel.
+func RunSmokeTest(cfg *mgrconfig.Config) (*report.Report, error) {
+ if !vm.AllowsOvercommit(cfg.Type) {
+ return nil, nil // No support for creating machines out of thin air.
+ }
+ osutil.MkdirAll(cfg.Workdir)
+ configFile := filepath.Join(cfg.Workdir, "manager.cfg")
+ if err := config.SaveFile(configFile, cfg); err != nil {
+ return nil, err
+ }
+ timeout := 30 * time.Minute * cfg.Timeouts.Scale
+ bin := filepath.Join(cfg.Syzkaller, "bin", "syz-manager")
+ output, retErr := osutil.RunCmd(timeout, "", bin, "-config", configFile, "-mode=smoke-test")
+ if retErr == nil {
+ return nil, nil
+ }
+ // If there was a kernel bug, report it to dashboard.
+ // Otherwise just save the output in a temp file and log an error, unclear what else we can do.
+ reportData, err := os.ReadFile(filepath.Join(cfg.Workdir, "report.json"))
+ if err != nil {
+ if os.IsNotExist(err) {
+ rep := &report.Report{
+ Title: "SYZFATAL: image testing failed w/o kernel bug",
+ Output: output,
+ }
+ return rep, nil
+ }
+ return nil, err
+ }
+ rep := new(report.Report)
+ if err := json.Unmarshal(reportData, rep); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal smoke test report: %w", err)
+ }
+ return rep, nil
+}
diff --git a/syz-ci/manager.go b/syz-ci/manager.go
index 547b5d9cc..d990a5a38 100644
--- a/syz-ci/manager.go
+++ b/syz-ci/manager.go
@@ -36,7 +36,6 @@ import (
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
"github.com/google/syzkaller/sys/targets"
- "github.com/google/syzkaller/vm"
)
// This is especially slightly longer than syzkaller rebuild period.
@@ -482,68 +481,30 @@ func (mgr *Manager) restartManager() {
}
func (mgr *Manager) testImage(imageDir string, info *BuildInfo) error {
+ testSem.Wait()
+ defer testSem.Signal()
+
log.Logf(0, "%v: testing image...", mgr.name)
mgrcfg, err := mgr.createTestConfig(imageDir, info)
if err != nil {
return fmt.Errorf("failed to create manager config: %w", err)
}
- if !vm.AllowsOvercommit(mgrcfg.Type) {
- return nil // No support for creating machines out of thin air.
- }
- osutil.MkdirAll(mgrcfg.Workdir)
- configFile := filepath.Join(mgrcfg.Workdir, "manager.cfg")
- if err := config.SaveFile(configFile, mgrcfg); err != nil {
+ rep, err := instance.RunSmokeTest(mgrcfg)
+ if err != nil {
+ mgr.Errorf("%s", err)
return err
- }
-
- testSem.Wait()
- defer testSem.Signal()
-
- timeout := 30 * time.Minute * mgrcfg.Timeouts.Scale
- bin := filepath.Join(mgrcfg.Syzkaller, "bin", "syz-manager")
- output, retErr := osutil.RunCmd(timeout, "", bin, "-config", configFile, "-mode=smoke-test")
- if retErr == nil {
+ } else if rep == nil {
return nil
}
-
- var verboseErr *osutil.VerboseError
- if errors.As(retErr, &verboseErr) {
- // Caller will log the error, so don't include full output.
- retErr = errors.New(verboseErr.Title)
- }
- // If there was a kernel bug, report it to dashboard.
- // Otherwise just save the output in a temp file and log an error, unclear what else we can do.
- reportData, err := os.ReadFile(filepath.Join(mgrcfg.Workdir, "report.json"))
- if err != nil {
- if os.IsNotExist(err) {
- mgr.Errorf("image testing failed w/o kernel bug")
- tmp, err := os.CreateTemp(mgr.workDir, "smoke-test-error")
- if err != nil {
- mgr.Errorf("failed to create smoke test error file: %v", err)
- } else {
- tmp.Write(output)
- tmp.Close()
- }
- } else {
- mgr.Errorf("failed to read smoke test report: %v", err)
- }
- } else {
- rep := new(report.Report)
- if err := json.Unmarshal(reportData, rep); err != nil {
- mgr.Errorf("failed to unmarshal smoke test report: %v", err)
- } else {
- rep.Title = fmt.Sprintf("%v test error: %v", mgr.mgrcfg.RepoAlias, rep.Title)
- retErr = errors.New(rep.Title)
- // There are usually no duplicates for boot errors, so we reset AltTitles.
- // But if we pass them, we would need to add the same prefix as for Title
- // in order to avoid duping boot bugs with non-boot bugs.
- rep.AltTitles = nil
- if err := mgr.reportBuildError(rep, info, imageDir); err != nil {
- mgr.Errorf("failed to report image error: %v", err)
- }
- }
+ rep.Title = fmt.Sprintf("%v test error: %v", mgr.mgrcfg.RepoAlias, rep.Title)
+ // There are usually no duplicates for boot errors, so we reset AltTitles.
+ // But if we pass them, we would need to add the same prefix as for Title
+ // in order to avoid duping boot bugs with non-boot bugs.
+ rep.AltTitles = nil
+ if err := mgr.reportBuildError(rep, info, imageDir); err != nil {
+ mgr.Errorf("failed to report image error: %v", err)
}
- return retErr
+ return fmt.Errorf("%s", rep.Title)
}
func (mgr *Manager) reportBuildError(rep *report.Report, info *BuildInfo, imageDir string) error {