From de2ea465e0fa9bd820feb6493445870ece9bacc5 Mon Sep 17 00:00:00 2001 From: Grigory Bazilevich Date: Mon, 29 Sep 2025 00:33:58 +0300 Subject: syz-manager: always save crashes and repros locally Save crashes and repros with corresponding kernel and syzkaller configs locally in syz-manager even when they are published to syz-dashboard, to be able to share the crashes with Linux Verification Center (linuxtesting.org). Signed-off-by: Grigory Bazilevich Signed-off-by: Sergey Zotov Co-authored-by: Sergey Zotov --- pkg/manager/crash.go | 10 ++++++++++ pkg/mgrconfig/load.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) (limited to 'pkg') diff --git a/pkg/manager/crash.go b/pkg/manager/crash.go index 6d0858837..cbc49580e 100644 --- a/pkg/manager/crash.go +++ b/pkg/manager/crash.go @@ -23,6 +23,7 @@ import ( type CrashStore struct { Tag string + Ctag []byte BaseDir string MaxCrashLogs int MaxReproLogs int @@ -35,8 +36,14 @@ const straceFileName = "strace.log" const MaxReproAttempts = 3 func NewCrashStore(cfg *mgrconfig.Config) *CrashStore { + ctag := "syzkaller-" + cfg.CtagSyzkaller + if cfg.CtagKernel != "" { + ctag = ctag + "\nlinux-" + cfg.CtagKernel + } + return &CrashStore{ Tag: cfg.Tag, + Ctag: []byte(ctag), BaseDir: cfg.Workdir, MaxCrashLogs: cfg.MaxCrashLogs, MaxReproLogs: MaxReproAttempts, @@ -91,6 +98,9 @@ func (cs *CrashStore) SaveCrash(crash *Crash) (bool, error) { writeOrRemove("tag", []byte(cs.Tag)) writeOrRemove("report", report.MergeReportBytes(reps)) writeOrRemove("machineInfo", crash.MachineInfo) + writeOrRemove("time", []byte(time.Now().Format("01-02-2006 15:04:05"))) + writeOrRemove("ctag", cs.Ctag) + if err := report.AddTitleStat(filepath.Join(dir, "title-stat"), reps); err != nil { return false, fmt.Errorf("report.AddTitleStat: %w", err) } diff --git a/pkg/mgrconfig/load.go b/pkg/mgrconfig/load.go index 38f0d0062..86064dc38 100644 --- a/pkg/mgrconfig/load.go +++ b/pkg/mgrconfig/load.go @@ -11,8 +11,10 @@ import ( "regexp" "runtime" "strings" + "time" "github.com/google/syzkaller/pkg/config" + "github.com/google/syzkaller/pkg/hash" "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/pkg/vminfo" "github.com/google/syzkaller/prog" @@ -38,6 +40,10 @@ type Derived struct { NoMutateCalls map[int]bool // Set of IDs of syscalls which should not be mutated. Timeouts targets.Timeouts + // Hashes of syzkaller and kernel configs for Linux Verification Center + CtagSyzkaller string + CtagKernel string + // Special debugging/development mode specified by VM type "none". // In this mode syz-manager does not start any VMs, but instead a user is supposed // to start syz-executor process in a VM manually. @@ -54,6 +60,7 @@ func LoadData(data []byte) (*Config, error) { if err := Complete(cfg); err != nil { return nil, err } + CompleteSyzCtagData(cfg, data) return cfg, nil } @@ -65,6 +72,7 @@ func LoadFile(filename string) (*Config, error) { if err := Complete(cfg); err != nil { return nil, err } + CompleteSyzCtagFile(cfg, filename) return cfg, nil } @@ -90,6 +98,21 @@ func LoadPartialFile(filename string) (*Config, error) { return cfg, nil } +func CompleteSyzCtagData(cfg *Config, data []byte) { + cfg.CtagSyzkaller = hash.String(data) + osutil.MkdirAll(filepath.Join(cfg.Workdir, "configs")) + osutil.WriteFile(filepath.Join(cfg.Workdir, "configs", "syzkaller-"+cfg.CtagSyzkaller+".cfg"), data) +} + +func CompleteSyzCtagFile(cfg *Config, filename string) { + confdata, err := os.ReadFile(filename) + if err != nil { + cfg.CtagSyzkaller = time.Now().Format(time.RFC3339) + return + } + CompleteSyzCtagData(cfg, confdata) +} + func DefaultValues() *Config { return &Config{ SSHUser: "root", @@ -174,6 +197,7 @@ func Complete(cfg *Config) error { return err } cfg.CompleteKernelDirs() + cfg.completeKernelCtag() if err := cfg.completeServices(); err != nil { return nil @@ -303,6 +327,36 @@ func (cfg *Config) KernelDirs() *KernelDirs { } } +func (cfg *Config) completeKernelCtag() { + confhash, conffile := findKernelConfig(cfg) + if confhash != "" { + cfg.CtagKernel = confhash + + confdata, _ := os.ReadFile(conffile) + osutil.MkdirAll(filepath.Join(cfg.Workdir, "configs")) + osutil.WriteFile(filepath.Join(cfg.Workdir, "configs", "linux-"+cfg.CtagKernel+".cfg"), confdata) + } +} + +func findKernelConfig(cfg *Config) (string, string) { + configs := [3]string{cfg.KernelBuildSrc, cfg.KernelObj, cfg.KernelSrc} + for _, s := range configs { + if _, err := os.Stat(filepath.Join(s, ".config")); err == nil { + confdata, _ := os.ReadFile(filepath.Join(s, ".config")) + return hash.String(confdata), filepath.Join(s, ".config") + } + if _, err := os.Stat(filepath.Join(s, "kernel.config")); err == nil { + confdata, _ := os.ReadFile(filepath.Join(s, "kernel.config")) + return hash.String(confdata), filepath.Join(s, "kernel.config") + } + if _, err := os.Stat(filepath.Join(filepath.Dir(s), "kernel.config")); err == nil { + confdata, _ := os.ReadFile(filepath.Join(filepath.Dir(s), "kernel.config")) + return hash.String(confdata), filepath.Join(filepath.Dir(s), "kernel.config") + } + } + return "", "" +} + func (cfg *Config) checkSSHParams() error { if cfg.SSHKey == "" { return nil -- cgit mrf-deployment