aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2023-06-15 14:14:53 +0200
committerAleksandr Nogikh <nogikh@google.com>2023-07-05 11:29:44 +0000
commite6cd3005e289a9d82272bb20a7173a4dbe75e55c (patch)
tree475211b6d82325160c6c7acc6f53550ee34190a2 /pkg
parentbb8ee958074bd1d8fc4d4feff290196c4d74a4c4 (diff)
pkg/vcs: disable Linux kernel configs based on crash.Type
More sanitizers means longer compilation times, more flakiness and risks of failures due to bugs in sanitizers themselves. If the crash type is known, determine the sanitizer that detected the problem and disable everything else.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/vcs/linux_configs.go54
-rw-r--r--pkg/vcs/linux_configs_test.go93
2 files changed, 146 insertions, 1 deletions
diff --git a/pkg/vcs/linux_configs.go b/pkg/vcs/linux_configs.go
index b54fed8fa..607a06285 100644
--- a/pkg/vcs/linux_configs.go
+++ b/pkg/vcs/linux_configs.go
@@ -3,7 +3,13 @@
package vcs
-import "github.com/google/syzkaller/pkg/kconfig"
+import (
+ "strings"
+
+ "github.com/google/syzkaller/pkg/debugtracer"
+ "github.com/google/syzkaller/pkg/kconfig"
+ "github.com/google/syzkaller/pkg/report/crash"
+)
// setLinuxTagConfigs() disables Linux kernel configurations depending on the Linux kernel version,
// which is determined by the git tags reachable from HEAD.
@@ -86,3 +92,49 @@ 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.
+ val := cf.Value("CMDLINE")
+ pos := strings.LastIndexByte(val, '"')
+ if pos >= 0 {
+ cf.Set("CMDLINE",
+ val[:pos]+" rcupdate.rcu_cpu_stall_suppress=1"+val[pos:])
+ }
+ },
+ 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") },
+ crash.AtomicSleep: func() { cf.Unset("DEBUG_ATOMIC_SLEEP") },
+ }
+ need := map[crash.Type]bool{}
+ for _, typ := range types {
+ if typ == crash.Warning {
+ // These are disabled together.
+ typ = crash.Bug
+ }
+ need[typ] = true
+ }
+ var disabled []string
+ for typ, f := range keep {
+ if need[typ] {
+ continue
+ }
+ f()
+ disabled = append(disabled, string(typ))
+ }
+ if len(disabled) > 0 {
+ dt.Log("disabling configs for %v, they are not needed", disabled)
+ }
+}
diff --git a/pkg/vcs/linux_configs_test.go b/pkg/vcs/linux_configs_test.go
new file mode 100644
index 000000000..6ea95645f
--- /dev/null
+++ b/pkg/vcs/linux_configs_test.go
@@ -0,0 +1,93 @@
+// Copyright 2023 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 vcs
+
+import (
+ "testing"
+
+ "github.com/google/syzkaller/pkg/debugtracer"
+ "github.com/google/syzkaller/pkg/kconfig"
+ "github.com/google/syzkaller/pkg/report/crash"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestDropLinuxSanitizerConfigs(t *testing.T) {
+ tests := []struct {
+ name string
+ types []crash.Type
+ test func(*testing.T, *kconfig.ConfigFile)
+ }{
+ {
+ name: "warning",
+ types: []crash.Type{crash.Warning},
+ test: func(t *testing.T, cf *kconfig.ConfigFile) {
+ assertConfigs(t, cf, "BUG")
+ assert.Equal(t,
+ `"param1=a param2=b rcupdate.rcu_cpu_stall_suppress=1"`,
+ cf.Value("CMDLINE"),
+ )
+ },
+ },
+ {
+ name: "kasan bug",
+ types: []crash.Type{crash.KASAN},
+ test: func(t *testing.T, cf *kconfig.ConfigFile) {
+ assertConfigs(t, cf, "KASAN")
+ },
+ },
+ {
+ name: "warning & kasan bug",
+ types: []crash.Type{crash.Warning, crash.KASAN},
+ test: func(t *testing.T, cf *kconfig.ConfigFile) {
+ assertConfigs(t, cf, "KASAN", "BUG")
+ },
+ },
+ {
+ name: "lockdep",
+ types: []crash.Type{crash.LockdepBug},
+ test: func(t *testing.T, cf *kconfig.ConfigFile) {
+ assertConfigs(t, cf, "LOCKDEP")
+ },
+ },
+ {
+ name: "rcu stall",
+ types: []crash.Type{crash.Hang},
+ test: func(t *testing.T, cf *kconfig.ConfigFile) {
+ assertConfigs(t, cf, "RCU_STALL_COMMON")
+ assert.Equal(t, `"param1=a param2=b"`, cf.Value("CMDLINE"))
+ },
+ },
+ }
+
+ const base = `
+CONFIG_CMDLINE="param1=a param2=b"
+CONFIG_BUG=y
+CONFIG_KASAN=y
+CONFIG_LOCKDEP=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_UBSAN=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+`
+ for _, test := range tests {
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ conf, err := kconfig.ParseConfigData([]byte(base), "base")
+ if err != nil {
+ t.Fatal(err)
+ }
+ setLinuxSanitizerConfigs(conf, test.types, &debugtracer.NullTracer{})
+ test.test(t, conf)
+ })
+ }
+}
+
+func assertConfigs(t *testing.T, cf *kconfig.ConfigFile, names ...string) {
+ var setConfigs []string
+ for _, name := range names {
+ if cf.Value(name) == kconfig.Yes {
+ setConfigs = append(setConfigs, name)
+ }
+ }
+ assert.ElementsMatch(t, setConfigs, names)
+}