From 2083933ab27c27d8d184d31cc8957851a4ec658f Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Wed, 14 Dec 2022 18:07:43 +0100 Subject: pkg/subsystem: add basic subsystem extraction code For now, recognize just the vfs subsystem and support per-repro-call subsystem inference. --- pkg/subsystem/extract.go | 52 +++++++++++++++++++++++++++++++++ pkg/subsystem/extract_test.go | 68 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 pkg/subsystem/extract.go create mode 100644 pkg/subsystem/extract_test.go (limited to 'pkg/subsystem') diff --git a/pkg/subsystem/extract.go b/pkg/subsystem/extract.go new file mode 100644 index 000000000..caf80636e --- /dev/null +++ b/pkg/subsystem/extract.go @@ -0,0 +1,52 @@ +// Copyright 2022 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 subsystem + +import ( + "regexp" + + "github.com/google/syzkaller/prog" + "github.com/google/syzkaller/sys/targets" +) + +type SubsystemExtractor struct { + CallToSubsystems func(call string) []string +} + +// Crash contains the subset of Crash fields relevant for subsystem extraction. +type Crash struct { + OS string + GuiltyFiles []string + SyzRepro string +} + +func (se *SubsystemExtractor) Extract(crash *Crash) []string { + retMap := map[string]bool{} + // Currently we only have the dumbest possible implementation of subsystem detection. + if crash.OS == targets.Linux { + for _, guiltyPath := range crash.GuiltyFiles { + if vfsPathRegexp.MatchString(guiltyPath) { + retMap["vfs"] = true + break + } + } + } + if se.CallToSubsystems != nil { + callSet, _, _ := prog.CallSet([]byte(crash.SyzRepro)) + for call := range callSet { + for _, subsystem := range se.CallToSubsystems(call) { + retMap[subsystem] = true + } + } + } + retSlice := []string{} + for name := range retMap { + retSlice = append(retSlice, name) + } + return retSlice +} + +var ( + vfsPathRegexp = regexp.MustCompile(`^fs/[^/]+\.c`) +) diff --git a/pkg/subsystem/extract_test.go b/pkg/subsystem/extract_test.go new file mode 100644 index 000000000..936f4fa8e --- /dev/null +++ b/pkg/subsystem/extract_test.go @@ -0,0 +1,68 @@ +// Copyright 2022 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 subsystem + +import ( + "sort" + "testing" + + "github.com/google/syzkaller/sys/targets" + "github.com/stretchr/testify/assert" +) + +func TestSimpleLinuxExtract(t *testing.T) { + se := &SubsystemExtractor{} + + ret := se.Extract(&Crash{ + OS: targets.Linux, + GuiltyFiles: []string{ + "fs/ext4/abc.c", + }, + }) + assert.Empty(t, ret, "the test should have found 0 subsystems") + + ret = se.Extract(&Crash{ + OS: targets.Linux, + GuiltyFiles: []string{ + "fs/ext4/abc.c", + "fs/def.c", + }, + }) + assert.Exactly(t, ret, []string{"vfs"}, "the test should have only found vfs") +} + +func TestProgCallRules(t *testing.T) { + se := &SubsystemExtractor{ + CallToSubsystems: func(call string) []string { + ret := map[string][]string{ + // Intentionally add some that are not present in the test below. + "test": {"test"}, + "syz_io_uring_setup": {"io_uring"}, + "ioctl$TIOCSETD": {"tty_ioctls", "tty"}, + // Some calls are also omitted to verify that the code works fine this way. + } + return ret[call] + }, + } + + ret := se.Extract(&Crash{ + OS: targets.Linux, + GuiltyFiles: []string{ + "mm/page-writeback.c", + }, + // nolint: lll + SyzRepro: `# https://syzkaller.appspot.com/bug?id=708185e841adf6ca28fc50b126fdf9825fd8ae43 +# See https://goo.gl/kgGztJ for information about syzkaller reproducers. +#{"repeat":true,"procs":1,"slowdown":1,"sandbox":"","close_fds":false} +r0 = syz_io_uring_setup(0x3ee4, &(0x7f0000000240), &(0x7f0000002000/0x2000)=nil, &(0x7f0000ffd000/0x3000)=nil, &(0x7f0000000100)=0x0, &(0x7f0000000140)=0x0) +socket$inet_udplite(0x2, 0x2, 0x88) +r3 = openat$ptmx(0xffffffffffffff9c, &(0x7f0000000040), 0x8a04, 0x0) +syz_io_uring_submit(r1, r2, &(0x7f0000000000)=@IORING_OP_READ=@pass_buffer={0x16, 0x0, 0x0, @fd_index=0x5, 0x0, 0x0}, 0x0) +ioctl$TIOCSETD(r3, 0x5423, &(0x7f0000000580)=0x3) +io_uring_enter(r0, 0x2ff, 0x0, 0x0, 0x0, 0x0)`, + }) + sort.Strings(ret) + assert.Exactlyf(t, ret, []string{"io_uring", "tty", "tty_ioctls"}, + "invalid resulting subsystems: %s", ret) +} -- cgit mrf-deployment