From f63b8696b67a1c47ecd4fced47215acd6805a14a Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Sun, 20 Oct 2024 22:55:31 +0200 Subject: 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. --- pkg/manager/http.go | 144 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 134 insertions(+), 10 deletions(-) (limited to 'pkg/manager/http.go') diff --git a/pkg/manager/http.go b/pkg/manager/http.go index 155765534..c94ce727f 100644 --- a/pkg/manager/http.go +++ b/pkg/manager/http.go @@ -51,6 +51,7 @@ type HTTPServer struct { StartTime time.Time Corpus *corpus.Corpus CrashStore *CrashStore + DiffStore *DiffFuzzerStore // Set dynamically. Fuzzer atomic.Pointer[fuzzer.Fuzzer] @@ -77,13 +78,15 @@ func (serv *HTTPServer) Serve() { handle("/syscalls", serv.httpSyscalls) handle("/corpus", serv.httpCorpus) handle("/corpus.db", serv.httpDownloadCorpus) - handle("/crash", serv.httpCrash) + if serv.CrashStore != nil { + handle("/crash", serv.httpCrash) + handle("/report", serv.httpReport) + } handle("/cover", serv.httpCover) handle("/subsystemcover", serv.httpSubsystemCover) handle("/modulecover", serv.httpModuleCover) handle("/prio", serv.httpPrio) handle("/file", serv.httpFile) - handle("/report", serv.httpReport) handle("/rawcover", serv.httpRawCover) handle("/rawcoverfiles", serv.httpRawCoverFiles) handle("/filterpcs", serv.httpFilterPCs) @@ -125,11 +128,15 @@ func (serv *HTTPServer) httpSummary(w http.ResponseWriter, r *http.Request) { Link: stat.Link, }) } - - var err error - if data.Crashes, err = serv.collectCrashes(serv.Cfg.Workdir); err != nil { - http.Error(w, fmt.Sprintf("failed to collect crashes: %v", err), http.StatusInternalServerError) - return + if serv.CrashStore != nil { + var err error + if data.Crashes, err = serv.collectCrashes(serv.Cfg.Workdir); err != nil { + http.Error(w, fmt.Sprintf("failed to collect crashes: %v", err), http.StatusInternalServerError) + return + } + } + if serv.DiffStore != nil { + data.PatchedOnly, data.AffectsBoth, data.InProgress = serv.collectDiffCrashes() } executeTemplate(w, summaryTemplate, data) } @@ -695,15 +702,61 @@ func (serv *HTTPServer) httpFilterPCs(w http.ResponseWriter, r *http.Request) { serv.httpCoverCover(w, r, DoFilterPCs) } -func (serv *HTTPServer) collectCrashes(workdir string) ([]*UICrashType, error) { - var repros map[string]bool +func (serv *HTTPServer) collectDiffCrashes() (patchedOnly, both, inProgress *UIDiffTable) { + for _, item := range serv.allDiffCrashes() { + if item.PatchedOnly() { + if patchedOnly == nil { + patchedOnly = &UIDiffTable{Title: "Patched-only"} + } + patchedOnly.List = append(patchedOnly.List, item) + } else if item.AffectsBoth() { + if both == nil { + both = &UIDiffTable{Title: "Affects both"} + } + both.List = append(both.List, item) + } else { + if inProgress == nil { + inProgress = &UIDiffTable{Title: "In Progress"} + } + inProgress.List = append(inProgress.List, item) + } + } + return +} + +func (serv *HTTPServer) allDiffCrashes() []UIDiffBug { + repros := serv.nowReproducing() + var list []UIDiffBug + for _, bug := range serv.DiffStore.List() { + list = append(list, UIDiffBug{ + DiffBug: bug, + Reproducing: repros[bug.Title], + }) + } + sort.Slice(list, func(i, j int) bool { + first, second := list[i], list[j] + firstPatched, secondPatched := first.PatchedOnly(), second.PatchedOnly() + if firstPatched != secondPatched { + return firstPatched + } + return first.Title < second.Title + }) + return list +} + +func (serv *HTTPServer) nowReproducing() map[string]bool { if reproLoop := serv.ReproLoop.Load(); reproLoop != nil { - repros = reproLoop.Reproducing() + return reproLoop.Reproducing() } + return nil +} + +func (serv *HTTPServer) collectCrashes(workdir string) ([]*UICrashType, error) { list, err := serv.CrashStore.BugList() if err != nil { return nil, err } + repros := serv.nowReproducing() var ret []*UICrashType for _, info := range list { ret = append(ret, makeUICrashType(info, serv.StartTime, repros)) @@ -788,9 +841,17 @@ type UISummaryData struct { Expert bool Stats []UIStat Crashes []*UICrashType + PatchedOnly *UIDiffTable + AffectsBoth *UIDiffTable + InProgress *UIDiffTable Log string } +type UIDiffTable struct { + Title string + List []UIDiffBug +} + type UIVMData struct { Name string VMs []UIVMInfo @@ -825,6 +886,11 @@ type UICrash struct { Active bool } +type UIDiffBug struct { + DiffBug + Reproducing bool +} + type UIStat struct { Name string Value string @@ -881,6 +947,7 @@ var summaryTemplate = pages.Create(` {{end}} +{{if .Crashes}} @@ -905,6 +972,63 @@ var summaryTemplate = pages.Create(` {{end}}
Crashes:
+{{end}} + +{{define "diff_crashes"}} + + + + + + + + {{range $bug := .List}} + + + + + + {{end}} +
{{.Title}}:
DescriptionBasePatched
{{$bug.Title}} + {{if gt $bug.Base.Crashes 0}} + {{$bug.Base.Crashes}} crashes + {{else if $bug.Base.NotCrashed}} + Not affected + {{else}} ? {{end}} + {{if $bug.Base.Report}} + [report] + {{end}} + + {{if gt $bug.Patched.Crashes 0}} + {{$bug.Patched.Crashes}} crashes + {{else}} ? {{end}} + {{if $bug.Patched.Report}} + [report] + {{end}} + {{if $bug.Patched.CrashLog}} + [crash log] + {{end}} + {{if $bug.Patched.Repro}} + [syz repro] + {{end}} + {{if $bug.Patched.ReproLog}} + [repro log] + {{end}} + {{if $bug.Reproducing}}[reproducing]{{end}} +
+{{end}} + +{{if .PatchedOnly}} +{{template "diff_crashes" .PatchedOnly}} +{{end}} + +{{if .AffectsBoth}} +{{template "diff_crashes" .AffectsBoth}} +{{end}} + +{{if .InProgress}} +{{template "diff_crashes" .InProgress}} +{{end}} Log:
-- cgit mrf-deployment