From 8ba1a581b0871089bc1d4df17c1d97f1a18357ff Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Thu, 22 Aug 2024 14:25:13 +0200 Subject: pkg/report: extract the syz-executor info For Linux bugs, extract the proc id and the prog id from the crash report. --- pkg/report/linux.go | 21 +++++++++++++++++++++ pkg/report/report.go | 7 +++++++ pkg/report/report_test.go | 21 +++++++++++++++------ pkg/report/testdata/linux/report/718 | 1 + pkg/report/testdata/linux/report/719 | 1 + pkg/report/testdata/linux/report/720 | 1 + 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/pkg/report/linux.go b/pkg/report/linux.go index 959089d70..216fcf18e 100644 --- a/pkg/report/linux.go +++ b/pkg/report/linux.go @@ -189,6 +189,7 @@ func (ctx *linux) Parse(output []byte) *Report { rep.reportPrefixLen = len(rep.Report) rep.Report = append(rep.Report, report...) setReportType(rep, oops, format) + ctx.setExecutorInfo(rep) if !rep.Corrupted { rep.Corrupted, rep.CorruptedReason = ctx.isCorrupted(title, report, format) } @@ -890,6 +891,26 @@ func (ctx *linux) isCorrupted(title string, report []byte, format oopsFormat) (b return false, "" } +var syzLinuxCommRe = regexp.MustCompile(` Comm: syz\.(\d+)\.(\d+) `) + +func (ctx *linux) setExecutorInfo(rep *Report) { + match := syzLinuxCommRe.FindSubmatch(rep.Report) + if match == nil { + return + } + info := &ExecutorInfo{} + var err error + info.ProcID, err = strconv.Atoi(string(match[1])) + if err != nil { + return + } + info.ExecID, err = strconv.Atoi(string(match[2])) + if err != nil { + return + } + rep.Executor = info +} + func linuxStallFrameExtractor(frames []string) string { // During rcu stalls and cpu lockups kernel loops in some part of code, // usually across several functions. When the stall is detected, traceback diff --git a/pkg/report/report.go b/pkg/report/report.go index 97b2e6aed..a0cdb7607 100644 --- a/pkg/report/report.go +++ b/pkg/report/report.go @@ -69,12 +69,19 @@ type Report struct { GuiltyFile string // Arbitrary information about the test VM, may be attached to the report by users of the package. MachineInfo []byte + // If the crash happened in the context of the syz-executor process, Executor will hold more info. + Executor *ExecutorInfo // reportPrefixLen is length of additional prefix lines that we added before actual crash report. reportPrefixLen int // symbolized is set if the report is symbolized. symbolized bool } +type ExecutorInfo struct { + ProcID int // ID of the syz-executor proc mentioned in the crash report. + ExecID int // The program the syz-executor was executing. +} + func (r Report) String() string { return fmt.Sprintf("crash: %v\n%s", r.Title, r.Report) } diff --git a/pkg/report/report_test.go b/pkg/report/report_test.go index 9671607ec..9afe33e6c 100644 --- a/pkg/report/report_test.go +++ b/pkg/report/report_test.go @@ -43,6 +43,7 @@ type ParseTest struct { Suppressed bool HasReport bool Report []byte + Executor string } func testParseFile(t *testing.T, reporter *Reporter, fn string) { @@ -105,6 +106,7 @@ func parseHeaderLine(t *testing.T, test *ParseTest, ln string) { endPrefix = "END: " corruptedPrefix = "CORRUPTED: " suppressedPrefix = "SUPPRESSED: " + executorPrefix = "EXECUTOR: " ) switch { case strings.HasPrefix(ln, "#"): @@ -138,6 +140,8 @@ func parseHeaderLine(t *testing.T, test *ParseTest, ln string) { default: t.Fatalf("unknown SUPPRESSED value %q", v) } + case strings.HasPrefix(ln, executorPrefix): + test.Executor = ln[len(executorPrefix):] default: t.Fatalf("unknown header field %q", ln) } @@ -159,7 +163,8 @@ func testParseImpl(t *testing.T, reporter *Reporter, test *ParseTest) { if rep != nil && rep.Type == unspecifiedType { t.Fatalf("unspecifiedType leaked outside") } - title, corrupted, corruptedReason, suppressed, typ, frame := "", false, "", false, crash.UnknownType, "" + title, corrupted, corruptedReason := "", false, "" + suppressed, typ, frame, executor := false, crash.UnknownType, "", "" var altTitles []string if rep != nil { title = rep.Title @@ -169,11 +174,15 @@ func testParseImpl(t *testing.T, reporter *Reporter, test *ParseTest) { suppressed = rep.Suppressed typ = rep.Type frame = rep.Frame + if rep.Executor != nil { + executor = fmt.Sprintf("proc=%d, id=%d", rep.Executor.ProcID, rep.Executor.ExecID) + } } sort.Strings(altTitles) sort.Strings(test.AltTitles) if title != test.Title || !reflect.DeepEqual(altTitles, test.AltTitles) || corrupted != test.Corrupted || - suppressed != test.Suppressed || typ != test.Type || test.Frame != "" && frame != test.Frame { + suppressed != test.Suppressed || typ != test.Type || test.Frame != "" && frame != test.Frame || + test.Executor != executor { if *flagUpdate && test.StartLine+test.EndLine == "" { updateReportTest(t, test, title, altTitles, corrupted, suppressed, typ, frame) } @@ -184,10 +193,10 @@ func testParseImpl(t *testing.T, reporter *Reporter, test *ParseTest) { for _, t := range test.AltTitles { wantAltTitles += "ALT: " + t + "\n" } - t.Fatalf("want:\nTITLE: %s\n%sTYPE: %v\nFRAME: %v\nCORRUPTED: %v\nSUPPRESSED: %v\n"+ - "got:\nTITLE: %s\n%sTYPE: %v\nFRAME: %v\nCORRUPTED: %v (%v)\nSUPPRESSED: %v", - test.Title, wantAltTitles, test.Type, test.Frame, test.Corrupted, test.Suppressed, - title, gotAltTitles, typ, frame, corrupted, corruptedReason, suppressed) + t.Fatalf("want:\nTITLE: %s\n%sTYPE: %v\nFRAME: %v\nCORRUPTED: %v\nSUPPRESSED: %v\nEXECUTOR: %v\n"+ + "got:\nTITLE: %s\n%sTYPE: %v\nFRAME: %v\nCORRUPTED: %v (%v)\nSUPPRESSED: %v\nEXECUTOR: %v\n", + test.Title, wantAltTitles, test.Type, test.Frame, test.Corrupted, test.Suppressed, test.Executor, + title, gotAltTitles, typ, frame, corrupted, corruptedReason, suppressed, executor) } if title != "" && len(rep.Report) == 0 { t.Fatalf("found crash message but report is empty") diff --git a/pkg/report/testdata/linux/report/718 b/pkg/report/testdata/linux/report/718 index 08e9c14b2..cadead591 100644 --- a/pkg/report/testdata/linux/report/718 +++ b/pkg/report/testdata/linux/report/718 @@ -2,6 +2,7 @@ TITLE: INFO: rcu detected stall in corrupted ALT: stall in corrupted TYPE: HANG CORRUPTED: Y +EXECUTOR: proc=0, id=104 [ 146.893110][ C1] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks: [ 146.894767][ C1] rcu: (detected by 1, t=10002 jiffies, g=4241, q=1639 ncpus=2) diff --git a/pkg/report/testdata/linux/report/719 b/pkg/report/testdata/linux/report/719 index 25a3db884..af46a7eba 100644 --- a/pkg/report/testdata/linux/report/719 +++ b/pkg/report/testdata/linux/report/719 @@ -2,6 +2,7 @@ TITLE: INFO: rcu detected stall in corrupted ALT: stall in corrupted TYPE: HANG CORRUPTED: Y +EXECUTOR: proc=2, id=4572 [ 576.777151][ C0] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks: [ 576.778800][ C0] rcu: Tasks blocked on level-0 rcu_node (CPUs 0-1): P30749/1:b..l P22934/1:b..l diff --git a/pkg/report/testdata/linux/report/720 b/pkg/report/testdata/linux/report/720 index 782c4682a..9a2ffe039 100644 --- a/pkg/report/testdata/linux/report/720 +++ b/pkg/report/testdata/linux/report/720 @@ -2,6 +2,7 @@ TITLE: INFO: rcu detected stall in corrupted ALT: stall in corrupted TYPE: HANG CORRUPTED: Y +EXECUTOR: proc=2, id=737 [ 204.021600][ C1] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks: [ 204.023224][ C1] rcu: Tasks blocked on level-0 rcu_node (CPUs 0-1): P9294/1:b..l -- cgit mrf-deployment