aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2025-07-01 10:15:11 +0200
committerTaras Madan <tarasmadan@google.com>2025-07-02 08:52:54 +0000
commitd94a0369a298b9dd3a9bc17d664840ea6f64401e (patch)
treec3b24a3497e8ec085e88f2a12f6ae70bddbd07c6
parentbc80e4f080d226b12fae367dc46bc54ac3681009 (diff)
dashboard/app: use crash types instead, no regexps
-rw-r--r--dashboard/app/graphs.go24
-rw-r--r--pkg/report/crash/types.go93
-rw-r--r--pkg/report/linux.go2
-rw-r--r--pkg/report/report.go4
-rw-r--r--pkg/report/report_test.go2
-rw-r--r--pkg/report/title_to_type.go28
-rw-r--r--pkg/vcs/linux_configs.go86
-rw-r--r--syz-manager/manager.go2
8 files changed, 176 insertions, 65 deletions
diff --git a/dashboard/app/graphs.go b/dashboard/app/graphs.go
index 9ba5d6313..068259135 100644
--- a/dashboard/app/graphs.go
+++ b/dashboard/app/graphs.go
@@ -13,6 +13,8 @@ import (
"strconv"
"time"
+ "github.com/google/syzkaller/pkg/report"
+ "github.com/google/syzkaller/pkg/report/crash"
db "google.golang.org/appengine/v2/datastore"
)
@@ -354,25 +356,25 @@ func createFoundBugs(c context.Context, bugs []*Bug) *uiGraph {
types := []struct {
name string
color string
- re *regexp.Regexp
+ pred crash.TypeGroupPred
}{
- {"KASAN", "Red", regexp.MustCompile(`^KASAN:`)},
- {"KMSAN", "Gold", regexp.MustCompile(`^KMSAN:`)},
- {"KCSAN", "Fuchsia", regexp.MustCompile(`^KCSAN:`)},
- {"mem safety", "OrangeRed", regexp.MustCompile(`^(WARNING: refcount bug|UBSAN: array-index|BUG: corrupted list|BUG: unable to handle kernel paging request)`)},
- {"mem leak", "MediumSeaGreen", regexp.MustCompile(`^memory leak`)},
- {"locking", "DodgerBlue", regexp.MustCompile(`^(BUG: sleeping function|BUG: spinlock recursion|BUG: using ([a-z_]+)\\(\\) in preemptible|inconsistent lock state|WARNING: still has locks held|possible deadlock|WARNING: suspicious RCU usage)`)},
- {"hangs/stalls", "LightSalmon", regexp.MustCompile(`^(BUG: soft lockup|INFO: rcu .* stall|INFO: task hung)`)},
+ {"KASAN", "Red", crash.Type.IsKASAN},
+ {"KMSAN", "Gold", crash.Type.IsKMSAN},
+ {"KCSAN", "Fuchsia", crash.Type.IsKCSAN},
+ {"mem safety", "OrangeRed", crash.Type.IsMemSafety},
+ {"mem leak", "MediumSeaGreen", crash.Type.IsMemoryLeak},
+ {"locking", "DodgerBlue", crash.Type.IsLockingBug},
+ {"hangs/stalls", "LightSalmon", crash.Type.IsHang},
// This must be at the end, otherwise "BUG:" will match other error types.
- {"DoS", "Violet", regexp.MustCompile(`^(BUG:|kernel BUG|divide error|Internal error in|kernel panic:|general protection fault)`)},
- {"other", "Gray", regexp.MustCompile(`.*`)},
+ {"DoS", "Violet", crash.Type.IsDoS},
+ {"other", "Gray", func(crash.Type) bool { return true }},
{projected, "LightGray", nil},
}
var sorted []time.Time
months := make(map[time.Time]map[string]int)
for _, bug := range bugs {
for _, typ := range types {
- if !typ.re.MatchString(bug.Title) {
+ if !typ.pred(report.TitleToCrashType(bug.Title)) {
continue
}
t := bug.FirstTime
diff --git a/pkg/report/crash/types.go b/pkg/report/crash/types.go
index 52fba0fbc..ad550fa08 100644
--- a/pkg/report/crash/types.go
+++ b/pkg/report/crash/types.go
@@ -6,21 +6,28 @@ package crash
type Type string
const (
- UnknownType = Type("")
- Hang = Type("HANG")
- MemoryLeak = Type("LEAK")
- DataRace = Type("DATARACE")
- UnexpectedReboot = Type("REBOOT")
- UBSAN = Type("UBSAN")
- Bug = Type("BUG")
- Warning = Type("WARNING")
- KASAN = Type("KASAN")
- KFENCE = Type("KFENCE")
- LockdepBug = Type("LOCKDEP")
- AtomicSleep = Type("ATOMIC_SLEEP")
- KMSAN = Type("KMSAN")
- SyzFailure = Type("SYZ_FAILURE")
+ UnknownType = Type("")
+ // keep-sorted start
+ AtomicSleep = Type("ATOMIC_SLEEP")
+ Bug = Type("BUG")
+ DoS = Type("DoS")
+ Hang = Type("HANG")
+ KASAN = Type("KASAN")
+ KCSAN = Type("KCSAN")
+ KCSANDataRace = Type("DATARACE")
+ KFENCE = Type("KFENCE")
+ KMSAN = Type("KMSAN")
+ LockdepBug = Type("LOCKDEP")
+ MemoryLeak = Type("LEAK")
+ MemorySafetyBUG = Type("MEMORY_SAFETY_BUG")
+ MemorySafetyUBSAN = Type("MEMORY_SAFETY_UBSAN")
+ MemorySafetyWARNING = Type("MEMORY_SAFETY_WARNING")
+ UBSAN = Type("UBSAN")
+ Warning = Type("WARNING")
+ // keep-sorted end
LostConnection = Type("LOST_CONNECTION")
+ SyzFailure = Type("SYZ_FAILURE")
+ UnexpectedReboot = Type("REBOOT")
)
func (t Type) String() string {
@@ -29,3 +36,61 @@ func (t Type) String() string {
}
return string(t)
}
+
+type TypeGroupPred func(Type) bool
+
+func (t Type) IsKASAN() bool {
+ return t == KASAN
+}
+
+func (t Type) IsKMSAN() bool {
+ return t == KMSAN
+}
+
+func (t Type) IsKCSAN() bool {
+ return t == KCSANDataRace || t == KCSAN
+}
+
+func (t Type) IsUBSAN() bool {
+ return t == UBSAN || t == MemorySafetyUBSAN
+}
+
+func (t Type) IsBUG() bool {
+ return t == Bug || t == MemorySafetyBUG
+}
+
+func (t Type) IsWarning() bool {
+ return t == Warning || t == MemorySafetyWARNING
+}
+
+func (t Type) IsBugOrWarning() bool {
+ return t.IsBUG() || t.IsWarning()
+}
+
+func (t Type) IsMemSafety() bool {
+ return t == MemorySafetyBUG || t == MemorySafetyWARNING || t == MemorySafetyUBSAN
+}
+
+func (t Type) IsMemoryLeak() bool {
+ return t == MemoryLeak
+}
+
+func (t Type) IsLockingBug() bool {
+ return t.IsLockdep() || t.IsAtomicSleep()
+}
+
+func (t Type) IsDoS() bool {
+ return t == Bug || t == DoS
+}
+
+func (t Type) IsHang() bool {
+ return t == Hang
+}
+
+func (t Type) IsLockdep() bool {
+ return t == LockdepBug
+}
+
+func (t Type) IsAtomicSleep() bool {
+ return t == AtomicSleep
+}
diff --git a/pkg/report/linux.go b/pkg/report/linux.go
index f714e55cd..ff5d6bf4e 100644
--- a/pkg/report/linux.go
+++ b/pkg/report/linux.go
@@ -188,7 +188,7 @@ func (ctx *linux) Parse(output []byte) *Report {
}
rep.reportPrefixLen = len(rep.Report)
rep.Report = append(rep.Report, report...)
- rep.Type = titleToCrashType(rep.Title)
+ rep.Type = TitleToCrashType(rep.Title)
setExecutorInfo(rep)
if !rep.Corrupted {
rep.Corrupted, rep.CorruptedReason = isCorrupted(title, report, format)
diff --git a/pkg/report/report.go b/pkg/report/report.go
index 3381607ea..44d4563e2 100644
--- a/pkg/report/report.go
+++ b/pkg/report/report.go
@@ -800,7 +800,7 @@ func simpleLineParser(output []byte, oopses []*oops, params *stackParams, ignore
rep.Report = output[rep.StartPos:]
rep.Corrupted = corrupted != ""
rep.CorruptedReason = corrupted
- rep.Type = titleToCrashType(rep.Title)
+ rep.Type = TitleToCrashType(rep.Title)
return rep
}
@@ -933,7 +933,7 @@ var groupGoRuntimeErrors = oops{
},
}
-func titleToCrashType(title string) crash.Type {
+func TitleToCrashType(title string) crash.Type {
for _, t := range titleToType {
for _, prefix := range t.includePrefixes {
if strings.HasPrefix(title, prefix) {
diff --git a/pkg/report/report_test.go b/pkg/report/report_test.go
index 739068787..2184cd411 100644
--- a/pkg/report/report_test.go
+++ b/pkg/report/report_test.go
@@ -208,7 +208,7 @@ func testFromReport(rep *Report) *ParseTest {
Corrupted: rep.Corrupted,
corruptedReason: rep.CorruptedReason,
Suppressed: rep.Suppressed,
- Type: titleToCrashType(rep.Title),
+ Type: TitleToCrashType(rep.Title),
Frame: rep.Frame,
Report: rep.Report,
}
diff --git a/pkg/report/title_to_type.go b/pkg/report/title_to_type.go
index 44f5ccaf9..61c7b6d9d 100644
--- a/pkg/report/title_to_type.go
+++ b/pkg/report/title_to_type.go
@@ -12,8 +12,29 @@ var titleToType = []struct {
crashType crash.Type
}{
{
+ includePrefixes: []string{
+ // keep-sorting start
+ "BUG: corrupted list",
+ "BUG: unable to handle kernel paging request",
+ // keep-sorting end
+ },
+ crashType: crash.MemorySafetyBUG,
+ },
+ {
+ includePrefixes: []string{
+ "WARNING: refcount bug",
+ },
+ crashType: crash.MemorySafetyWARNING,
+ },
+ {
+ includePrefixes: []string{
+ "UBSAN: array-index",
+ },
+ crashType: crash.MemorySafetyUBSAN,
+ },
+ {
includePrefixes: []string{"KCSAN: data-race"},
- crashType: crash.DataRace,
+ crashType: crash.KCSANDataRace,
},
{
includePrefixes: []string{
@@ -23,6 +44,7 @@ var titleToType = []struct {
"BUG: rwlock",
"BUG: spinlock",
"BUG: still has locks held in",
+ "BUG: using", // BUG: using ... in preemptible ...
"WARNING: bad unlock balance in",
"WARNING: held lock freed in",
"WARNING: lock held",
@@ -53,7 +75,6 @@ var titleToType = []struct {
includePrefixes: []string{
// keep-sorted start
"BUG: bad usercopy in",
- "BUG: corrupted list in",
"kernel BUG ",
// keep-sorted end
},
@@ -90,7 +111,6 @@ var titleToType = []struct {
// keep-sorted start
"Alignment trap in",
"BUG: Object already free",
- "BUG: unable to handle kernel",
"Internal error in",
"PANIC: double fault",
"Unhandled fault in",
@@ -109,7 +129,7 @@ var titleToType = []struct {
"unregister_netdevice: waiting for DEV to become free",
// keep-sorted end
},
- crashType: crash.UnknownType,
+ crashType: crash.DoS,
},
{
includePrefixes: []string{"unexpected kernel reboot"},
diff --git a/pkg/vcs/linux_configs.go b/pkg/vcs/linux_configs.go
index 8d972edd3..8b59abbc0 100644
--- a/pkg/vcs/linux_configs.go
+++ b/pkg/vcs/linux_configs.go
@@ -99,46 +99,70 @@ func setLinuxTagConfigs(cf *kconfig.ConfigFile, tags map[string]bool) {
// setLinuxSanitizerConfigs() removes Linux kernel sanitizers that are not necessary
// to trigger the specified crash types.
func setLinuxSanitizerConfigs(cf *kconfig.ConfigFile, types []crash.Type, dt debugtracer.DebugTracer) {
- keep := map[crash.Type]func(){
- crash.Hang: func() {
- cf.Unset("RCU_STALL_COMMON")
- cf.Unset("LOCKUP_DETECTOR")
- cf.Unset("SOFTLOCKUP_DETECTOR")
- cf.Unset("HARDLOCKUP_DETECTOR")
- cf.Unset("DETECT_HUNG_TASK")
- // It looks like it's the only reliable way to completely disable hung errors.
- cmdline := cf.Value("CMDLINE")
- pos := strings.LastIndexByte(cmdline, '"')
- const rcuStallSuppress = "rcupdate.rcu_cpu_stall_suppress=1"
- if pos >= 0 && !strings.Contains(cmdline, rcuStallSuppress) {
- cf.Set("CMDLINE", cmdline[:pos]+" "+rcuStallSuppress+cmdline[pos:])
- }
+ keep := map[string]struct {
+ pred crash.TypeGroupPred
+ disabler func()
+ }{
+ "hang": {
+ pred: crash.Type.IsHang,
+ disabler: func() {
+ cf.Unset("RCU_STALL_COMMON")
+ cf.Unset("LOCKUP_DETECTOR")
+ cf.Unset("SOFTLOCKUP_DETECTOR")
+ cf.Unset("HARDLOCKUP_DETECTOR")
+ cf.Unset("DETECT_HUNG_TASK")
+ // It looks like it's the only reliable way to completely disable hung errors.
+ cmdline := cf.Value("CMDLINE")
+ pos := strings.LastIndexByte(cmdline, '"')
+ const rcuStallSuppress = "rcupdate.rcu_cpu_stall_suppress=1"
+ if pos >= 0 && !strings.Contains(cmdline, rcuStallSuppress) {
+ cf.Set("CMDLINE", cmdline[:pos]+" "+rcuStallSuppress+cmdline[pos:])
+ }
+ },
+ },
+ "memleak": {
+ pred: crash.Type.IsMemoryLeak,
+ disabler: func() { cf.Unset("DEBUG_KMEMLEAK") },
+ },
+ "ubsan": {
+ pred: crash.Type.IsUBSAN,
+ disabler: func() { cf.Unset("UBSAN") },
},
- crash.MemoryLeak: func() { cf.Unset("DEBUG_KMEMLEAK") },
- crash.UBSAN: func() { cf.Unset("UBSAN") },
- crash.Bug: func() { cf.Unset("BUG") },
- crash.KASAN: func() { cf.Unset("KASAN") },
- crash.LockdepBug: func() {
- cf.Unset("LOCKDEP")
- cf.Unset("PROVE_LOCKING") // it selects LOCKDEP
+ "bug_or_warning": {
+ pred: crash.Type.IsBugOrWarning,
+ disabler: func() { cf.Unset("BUG") },
+ },
+ "kasan": {
+ pred: crash.Type.IsKASAN,
+ disabler: func() { cf.Unset("KASAN") },
+ },
+ "locking": {
+ pred: crash.Type.IsLockdep,
+ disabler: func() {
+ cf.Unset("LOCKDEP")
+ cf.Unset("PROVE_LOCKING") // it selects LOCKDEP
+ },
+ },
+ "atomic_sleep": {
+ pred: crash.Type.IsAtomicSleep,
+ disabler: func() { cf.Unset("DEBUG_ATOMIC_SLEEP") },
},
- crash.AtomicSleep: func() { cf.Unset("DEBUG_ATOMIC_SLEEP") },
}
- need := map[crash.Type]bool{}
+ need := map[string]bool{}
for _, typ := range types {
- if typ == crash.Warning {
- // These are disabled together.
- typ = crash.Bug
+ for keepName, funcs := range keep {
+ if funcs.pred(typ) {
+ need[keepName] = true
+ }
}
- need[typ] = true
}
var disabled []string
- for typ, f := range keep {
- if need[typ] {
+ for categoryName, funcs := range keep {
+ if need[categoryName] {
continue
}
- f()
- disabled = append(disabled, string(typ))
+ funcs.disabler()
+ disabled = append(disabled, categoryName)
}
if len(disabled) > 0 {
dt.Log("disabling configs for %v, they are not needed", disabled)
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index b494df213..9e704c0fb 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -696,7 +696,7 @@ func (mgr *Manager) saveCrash(crash *manager.Crash) bool {
mgr.memoryLeakFrames[crash.Frame] = true
mgr.mu.Unlock()
}
- if crash.Type == crash_pkg.DataRace {
+ if crash.Type == crash_pkg.KCSANDataRace {
mgr.mu.Lock()
mgr.dataRaceFrames[crash.Frame] = true
mgr.mu.Unlock()