aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/subsystem
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2023-01-20 18:00:47 +0100
committerAleksandr Nogikh <wp32pw@gmail.com>2023-02-10 14:34:44 +0100
commit5ca014a29eab3dcdecd58d34c0a332fa78958872 (patch)
tree12815af4043ba70470f07aa16ac447b10cc29acd /pkg/subsystem
parent3a4c5e2da302d43152f2e8b1362d8568c0d57e6e (diff)
pkg/subsystem: add the basic caller-facing interface
Users of the pkg/subsystem are only interested in 1) Fetching the list of subsystems for a given OS. 2) Matching a crash against the extracted set of subsystems.
Diffstat (limited to 'pkg/subsystem')
-rw-r--r--pkg/subsystem/list.go32
-rw-r--r--pkg/subsystem/raw_extractor.go48
-rw-r--r--pkg/subsystem/raw_extractor_test.go69
3 files changed, 149 insertions, 0 deletions
diff --git a/pkg/subsystem/list.go b/pkg/subsystem/list.go
new file mode 100644
index 000000000..737ab859e
--- /dev/null
+++ b/pkg/subsystem/list.go
@@ -0,0 +1,32 @@
+// 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 subsystem
+
+import (
+ "github.com/google/syzkaller/pkg/subsystem/entity"
+)
+
+// In general, it's not correct to assume that subsystems are only determined by target.OS,
+// because subsystems are related not to the user interface of the OS kernel, but rather to
+// the OS kernel implementation.
+//
+// For example, during fuzzing we can treat gVisor in the same way as any other Linux kernel.
+// In reality, however, not a single MAINTAINERS-based rule will work on the gVisor codebase.
+//
+// Therefore, subsystem lists have to be a completely different entity.
+
+var (
+ lists = make(map[string][]*entity.Subsystem)
+)
+
+func RegisterList(name string, list []*entity.Subsystem) {
+ if _, ok := lists[name]; ok {
+ panic(name + " subsystem list already exists!")
+ }
+ lists[name] = list
+}
+
+func GetList(name string) []*entity.Subsystem {
+ return lists[name]
+}
diff --git a/pkg/subsystem/raw_extractor.go b/pkg/subsystem/raw_extractor.go
new file mode 100644
index 000000000..4a86b1f6b
--- /dev/null
+++ b/pkg/subsystem/raw_extractor.go
@@ -0,0 +1,48 @@
+// 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 subsystem
+
+import (
+ "github.com/google/syzkaller/pkg/subsystem/entity"
+ "github.com/google/syzkaller/pkg/subsystem/match"
+ "github.com/google/syzkaller/prog"
+)
+
+// rawExtractor performs low-level subsystem matching (directly by a path or a syscall).
+type rawExtractor struct {
+ matcher *match.PathMatcher
+ perCall map[string][]*entity.Subsystem
+}
+
+func makeRawExtractor(list []*entity.Subsystem) *rawExtractor {
+ ret := &rawExtractor{
+ matcher: match.MakePathMatcher(list),
+ perCall: make(map[string][]*entity.Subsystem),
+ }
+ for _, subsystem := range list {
+ for _, call := range subsystem.Syscalls {
+ ret.perCall[call] = append(ret.perCall[call], subsystem)
+ }
+ }
+ return ret
+}
+
+func (e *rawExtractor) FromPath(path string) []*entity.Subsystem {
+ return e.matcher.Match(path)
+}
+
+func (e *rawExtractor) FromProg(progBytes []byte) []*entity.Subsystem {
+ calls := make(map[*entity.Subsystem]struct{})
+ progCalls, _, _ := prog.CallSet(progBytes)
+ for call := range progCalls {
+ for _, subsystem := range e.perCall[call] {
+ calls[subsystem] = struct{}{}
+ }
+ }
+ list := []*entity.Subsystem{}
+ for key := range calls {
+ list = append(list, key)
+ }
+ return list
+}
diff --git a/pkg/subsystem/raw_extractor_test.go b/pkg/subsystem/raw_extractor_test.go
new file mode 100644
index 000000000..9d221af86
--- /dev/null
+++ b/pkg/subsystem/raw_extractor_test.go
@@ -0,0 +1,69 @@
+// 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 subsystem
+
+import (
+ "testing"
+
+ "github.com/google/syzkaller/pkg/subsystem/entity"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSubsystemExtractor(t *testing.T) {
+ ioUring := &entity.Subsystem{
+ Name: "io_uring",
+ PathRules: []entity.PathRule{
+ {
+ IncludeRegexp: `io_uring/.*`,
+ },
+ },
+ Syscalls: []string{"syz_io_uring_setup"},
+ }
+ security := &entity.Subsystem{
+ Name: "security",
+ PathRules: []entity.PathRule{
+ {
+ IncludeRegexp: `security/.*`,
+ ExcludeRegexp: `security/selinux/.*`,
+ },
+ {
+ IncludeRegexp: `net/ipv6/calipso\.c`,
+ },
+ },
+ }
+ net := &entity.Subsystem{
+ Name: "net",
+ PathRules: []entity.PathRule{
+ {
+ IncludeRegexp: `net/.*`,
+ },
+ },
+ }
+ obj := makeRawExtractor([]*entity.Subsystem{ioUring, security, net})
+
+ // Verify path matching.
+ assert.ElementsMatch(t, obj.FromPath(`io_uring/file.c`), []*entity.Subsystem{ioUring})
+ assert.ElementsMatch(t, obj.FromPath(`security/file.c`), []*entity.Subsystem{security})
+ assert.ElementsMatch(t, obj.FromPath(`security/selinux/file.c`), []*entity.Subsystem{})
+ assert.ElementsMatch(t, obj.FromPath(`net/ipv6/calipso.c`), []*entity.Subsystem{net, security})
+
+ // Verify prog matching.
+ // nolint: lll
+ assert.ElementsMatch(t, obj.FromProg([]byte(
+ `# 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)=<r1=>0x0, &(0x7f0000000140)=<r2=>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)`)),
+ []*entity.Subsystem{ioUring})
+ // nolint: lll
+ assert.ElementsMatch(t, obj.FromProg([]byte(
+ `syz_mount_image$nilfs2(&(0x7f0000000000), &(0x7f0000000100)='./file0\x00', 0x100000, 0x3b, &(0x7f0000000200)=[{&(0x7f0000011240)="02", 0x1}, {&(0x7f0000012a40)="03000000", 0x4, 0x1}], 0x0, &(0x7f00000131c0), 0x1)
+openat$incfs(0xffffffffffffff9c, &(0x7f0000000000)='.pending_reads\x00', 0x4040, 0x0)`)),
+ []*entity.Subsystem{})
+}