diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2023-06-15 14:14:53 +0200 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2023-07-05 11:29:44 +0000 |
| commit | e6cd3005e289a9d82272bb20a7173a4dbe75e55c (patch) | |
| tree | 475211b6d82325160c6c7acc6f53550ee34190a2 /pkg | |
| parent | bb8ee958074bd1d8fc4d4feff290196c4d74a4c4 (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.go | 54 | ||||
| -rw-r--r-- | pkg/vcs/linux_configs_test.go | 93 |
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) +} |
