diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2024-10-20 22:55:31 +0200 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2024-10-25 12:08:02 +0000 |
| commit | f63b8696b67a1c47ecd4fced47215acd6805a14a (patch) | |
| tree | c7d5795c124fdc9a99b309db8ed75f56b2c6ffe9 /pkg/manager/diff.go | |
| parent | c0390c277e5fcda8d7288b717ff952e01dcdcb8d (diff) | |
tools: add a syz-diff tool
This is the prototype version of the patch series fuzzing functionality
based on the syzkaller fuzzing engine.
The tool takes two syzkaller configs -- one for the base kernel, one for
the patched kernel. Optionally the patch itself can be also provided.
syz-diff will consider a bug patched-only if:
1) It happened while fuzzing the patched kernel.
2) It was never observed on the base kernel.
3) The tool found a repro on the patched kernel.
4) The repro did not crash the base kernel.
Diffstat (limited to 'pkg/manager/diff.go')
| -rw-r--r-- | pkg/manager/diff.go | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/pkg/manager/diff.go b/pkg/manager/diff.go new file mode 100644 index 000000000..76e2b97ff --- /dev/null +++ b/pkg/manager/diff.go @@ -0,0 +1,139 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package manager + +import ( + "fmt" + "path/filepath" + "sync" + "time" + + "github.com/google/syzkaller/pkg/log" + "github.com/google/syzkaller/pkg/osutil" +) + +type DiffBug struct { + Title string + Base DiffBugInfo + Patched DiffBugInfo +} + +func (bug DiffBug) PatchedOnly() bool { + return bug.Base.NotCrashed && bug.Patched.Crashes > 0 +} + +func (bug DiffBug) AffectsBoth() bool { + return bug.Base.Crashes > 0 && bug.Patched.Crashes > 0 +} + +type DiffBugInfo struct { + Crashes int // Count of detected crashes. + NotCrashed bool // If were proven not to crash by running a repro. + + // File paths. + Report string + Repro string + ReproLog string + CrashLog string +} + +// DiffFuzzerStore provides the functionality of a database of the patch fuzzing. +type DiffFuzzerStore struct { + BasePath string + + mu sync.Mutex + bugs map[string]*DiffBug +} + +func (s *DiffFuzzerStore) BaseCrashed(title string, report []byte) { + s.patch(title, func(obj *DiffBug) { + obj.Base.Crashes++ + if len(report) > 0 { + obj.Base.Report = s.saveFile(title, "base_report", report) + } + }) +} + +func (s *DiffFuzzerStore) EverCrashedBase(title string) bool { + s.mu.Lock() + defer s.mu.Unlock() + obj := s.bugs[title] + return obj != nil && obj.Base.Crashes > 0 +} + +func (s *DiffFuzzerStore) BaseNotCrashed(title string) { + s.patch(title, func(obj *DiffBug) { + if obj.Base.Crashes == 0 { + obj.Base.NotCrashed = true + } + }) +} + +func (s *DiffFuzzerStore) PatchedCrashed(title string, report, log []byte) { + s.patch(title, func(obj *DiffBug) { + obj.Patched.Crashes++ + if len(report) > 0 { + obj.Patched.Report = s.saveFile(title, "patched_report", report) + } + if len(log) > 0 && obj.Patched.CrashLog == "" { + obj.Patched.CrashLog = s.saveFile(title, "patched_crash_log", log) + } + }) +} + +func (s *DiffFuzzerStore) SaveRepro(result *ReproResult) { + title := result.Crash.Report.Title + if result.Repro != nil { + // If there's a repro, save under the new title. + title = result.Repro.Report.Title + } + + now := time.Now().Unix() + crashLog := fmt.Sprintf("%v.crash.log", now) + s.saveFile(title, crashLog, result.Crash.Output) + log.Logf(0, "%q: saved crash log into %s", title, crashLog) + + s.patch(title, func(obj *DiffBug) { + if result.Repro != nil { + obj.Patched.Repro = s.saveFile(title, reproFileName, result.Repro.Prog.Serialize()) + } + if result.Stats != nil { + reproLog := fmt.Sprintf("%v.repro.log", now) + obj.Patched.ReproLog = s.saveFile(title, reproLog, result.Stats.FullLog()) + log.Logf(0, "%q: saved repro log into %s", title, reproLog) + } + }) +} + +func (s *DiffFuzzerStore) List() []DiffBug { + s.mu.Lock() + defer s.mu.Unlock() + var list []DiffBug + for _, obj := range s.bugs { + list = append(list, *obj) + } + return list +} + +func (s *DiffFuzzerStore) saveFile(title, name string, data []byte) string { + hash := crashHash(title) + path := filepath.Join(s.BasePath, "crashes", hash) + osutil.MkdirAll(path) + osutil.WriteFile(filepath.Join(path, name), data) + return filepath.Join("crashes", hash, name) +} + +func (s *DiffFuzzerStore) patch(title string, cb func(*DiffBug)) { + s.mu.Lock() + defer s.mu.Unlock() + if s.bugs == nil { + s.bugs = map[string]*DiffBug{} + } + obj, ok := s.bugs[title] + if !ok { + obj = &DiffBug{Title: title} + s.bugs[title] = obj + } + cb(obj) +} |
