aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-04-06 18:46:49 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-04-06 18:47:56 +0200
commit4daf8570eba286299489fc3ebc7d788c458bb47a (patch)
tree99b413a3fad8b7f7bf87c6a1fe957aa0a6112d75 /pkg
parent48a846e42b1ef210d410b783656c59d5c2827e11 (diff)
pkg/host: explain why syscalls are disabled
Diffstat (limited to 'pkg')
-rw-r--r--pkg/host/host.go27
-rw-r--r--pkg/host/host_akaros.go9
-rw-r--r--pkg/host/host_freebsd.go9
-rw-r--r--pkg/host/host_fuchsia.go9
-rw-r--r--pkg/host/host_linux.go127
-rw-r--r--pkg/host/host_linux_test.go37
-rw-r--r--pkg/host/host_netbsd.go9
-rw-r--r--pkg/host/host_test.go45
-rw-r--r--pkg/host/host_windows.go9
9 files changed, 162 insertions, 119 deletions
diff --git a/pkg/host/host.go b/pkg/host/host.go
new file mode 100644
index 000000000..f3acd05d9
--- /dev/null
+++ b/pkg/host/host.go
@@ -0,0 +1,27 @@
+// Copyright 2018 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 host
+
+import (
+ "github.com/google/syzkaller/prog"
+)
+
+// DetectSupportedSyscalls returns list on supported and unsupported syscalls on the host.
+// For unsupported syscalls it also returns reason as to why it is unsupported.
+func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Syscall]bool, map[*prog.Syscall]string, error) {
+ supported := make(map[*prog.Syscall]bool)
+ unsupported := make(map[*prog.Syscall]string)
+ for _, c := range target.Syscalls {
+ ok, reason := isSupported(c, sandbox)
+ if ok {
+ supported[c] = true
+ } else {
+ if reason == "" {
+ reason = "unknown"
+ }
+ unsupported[c] = reason
+ }
+ }
+ return supported, unsupported, nil
+}
diff --git a/pkg/host/host_akaros.go b/pkg/host/host_akaros.go
index 91ee49a7d..9478c7cac 100644
--- a/pkg/host/host_akaros.go
+++ b/pkg/host/host_akaros.go
@@ -9,13 +9,8 @@ import (
"github.com/google/syzkaller/prog"
)
-// DetectSupportedSyscalls returns list on supported syscalls on host.
-func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Syscall]bool, error) {
- supported := make(map[*prog.Syscall]bool)
- for _, c := range target.Syscalls {
- supported[c] = true
- }
- return supported, nil
+func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
+ return true, ""
}
func EnableFaultInjection() error {
diff --git a/pkg/host/host_freebsd.go b/pkg/host/host_freebsd.go
index 39e8655c4..bada10ec7 100644
--- a/pkg/host/host_freebsd.go
+++ b/pkg/host/host_freebsd.go
@@ -7,13 +7,8 @@ import (
"github.com/google/syzkaller/prog"
)
-// DetectSupportedSyscalls returns list on supported syscalls on host.
-func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Syscall]bool, error) {
- supported := make(map[*prog.Syscall]bool)
- for _, c := range target.Syscalls {
- supported[c] = true
- }
- return supported, nil
+func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
+ return true, ""
}
func EnableFaultInjection() error {
diff --git a/pkg/host/host_fuchsia.go b/pkg/host/host_fuchsia.go
index b145961df..87143d768 100644
--- a/pkg/host/host_fuchsia.go
+++ b/pkg/host/host_fuchsia.go
@@ -9,13 +9,8 @@ import (
"github.com/google/syzkaller/prog"
)
-// DetectSupportedSyscalls returns list on supported syscalls on host.
-func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Syscall]bool, error) {
- supported := make(map[*prog.Syscall]bool)
- for _, c := range target.Syscalls {
- supported[c] = true
- }
- return supported, nil
+func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
+ return true, ""
}
func EnableFaultInjection() error {
diff --git a/pkg/host/host_linux.go b/pkg/host/host_linux.go
index d5ab3a495..02392a4b0 100644
--- a/pkg/host/host_linux.go
+++ b/pkg/host/host_linux.go
@@ -10,15 +10,15 @@ import (
"runtime"
"strconv"
"strings"
+ "sync"
"syscall"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
)
-// DetectSupportedSyscalls returns list on supported syscalls on host.
-func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Syscall]bool, error) {
- // There are 3 possible strategies:
+func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
+ // There are 3 possible strategies for detecting supported syscalls:
// 1. Executes all syscalls with presumably invalid arguments and check for ENOprog.
// But not all syscalls are safe to execute. For example, pause will hang,
// while setpgrp will push the process into own process group.
@@ -27,18 +27,9 @@ func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Sys
// For example, on x86_64 it says that sendfile is not present (only sendfile64).
// 3. Check sys_syscallname in /proc/kallsyms.
// Requires CONFIG_KALLSYMS. Seems to be the most reliable. That's what we use here.
-
- kallsyms, _ := ioutil.ReadFile("/proc/kallsyms")
- supported := make(map[*prog.Syscall]bool)
- for _, c := range target.Syscalls {
- if isSupported(sandbox, kallsyms, c) {
- supported[c] = true
- }
- }
- return supported, nil
-}
-
-func isSupported(sandbox string, kallsyms []byte, c *prog.Syscall) bool {
+ kallsymsOnce.Do(func() {
+ kallsyms, _ = ioutil.ReadFile("/proc/kallsyms")
+ })
if strings.HasPrefix(c.CallName, "syz_") {
return isSupportedSyzkall(sandbox, c)
}
@@ -49,42 +40,52 @@ func isSupported(sandbox string, kallsyms []byte, c *prog.Syscall) bool {
return isSupportedOpenAt(c)
}
if len(kallsyms) == 0 {
- return true
+ return true, ""
}
name := c.CallName
if newname := kallsymsMap[name]; newname != "" {
name = newname
}
- return bytes.Contains(kallsyms, []byte(" T sys_"+name+"\n"))
+ if !bytes.Contains(kallsyms, []byte(" T sys_"+name+"\n")) {
+ return false, fmt.Sprintf("sys_%v is not present in /proc/kallsyms", name)
+ }
+ return true, ""
}
// Some syscall names diverge in __NR_* consts and kallsyms.
// umount2 is renamed to umount in arch/x86/entry/syscalls/syscall_64.tbl.
// Where umount is renamed to oldumount is unclear.
-var kallsymsMap = map[string]string{
- "umount": "oldumount",
- "umount2": "umount",
-}
+var (
+ kallsyms []byte
+ kallsymsOnce sync.Once
+ kallsymsMap = map[string]string{
+ "umount": "oldumount",
+ "umount2": "umount",
+ }
+)
-func isSupportedSyzkall(sandbox string, c *prog.Syscall) bool {
+func isSupportedSyzkall(sandbox string, c *prog.Syscall) (bool, string) {
switch c.CallName {
case "syz_open_dev":
if _, ok := c.Args[0].(*prog.ConstType); ok {
// This is for syz_open_dev$char/block.
// They are currently commented out, but in case one enables them.
- return true
+ return true, ""
}
fname, ok := extractStringConst(c.Args[0])
if !ok {
panic("first open arg is not a pointer to string const")
}
if syscall.Getuid() != 0 || sandbox == "setuid" {
- return false
+ return false, "only supported under root with sandbox=none/namespace"
}
var check func(dev string) bool
check = func(dev string) bool {
if !strings.Contains(dev, "#") {
- return osutil.IsExist(dev)
+ if !osutil.IsExist(dev) {
+ return false
+ }
+ return true
}
for i := 0; i < 10; i++ {
if check(strings.Replace(dev, "#", strconv.Itoa(i), 1)) {
@@ -93,59 +94,80 @@ func isSupportedSyzkall(sandbox string, c *prog.Syscall) bool {
}
return false
}
- return check(fname)
+ if !check(fname) {
+ return false, fmt.Sprintf("file %v does not exist", fname)
+ }
+ return true, ""
case "syz_open_procfs":
- return true
+ return true, ""
case "syz_open_pts":
- return true
+ return true, ""
case "syz_fuse_mount":
if syscall.Getuid() != 0 || sandbox == "setuid" {
- return false
+ return false, "only supported under root with sandbox=none/namespace"
+ }
+ if !osutil.IsExist("/dev/fuse") {
+ return false, "/dev/fuse does not exist"
}
- return osutil.IsExist("/dev/fuse")
+ return true, ""
case "syz_fuseblk_mount":
if syscall.Getuid() != 0 || sandbox == "setuid" {
- return false
+ return false, "only supported under root with sandbox=none/namespace"
+ }
+ if !osutil.IsExist("/dev/fuse") {
+ return false, "/dev/fuse does not exist"
}
- return osutil.IsExist("/dev/fuse")
+ return true, ""
case "syz_emit_ethernet", "syz_extract_tcp_res":
fd, err := syscall.Open("/dev/net/tun", syscall.O_RDWR, 0)
- if err == nil {
- syscall.Close(fd)
+ if err != nil {
+ return false, fmt.Sprintf("open(/dev/net/tun) failed: %v", err)
}
- return err == nil
+ syscall.Close(fd)
+ return true, ""
case "syz_kvm_setup_cpu":
switch c.Name {
case "syz_kvm_setup_cpu$x86":
- return runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
+ if runtime.GOARCH == "amd64" || runtime.GOARCH == "386" {
+ return true, ""
+ }
case "syz_kvm_setup_cpu$arm64":
- return runtime.GOARCH == "arm64"
+ if runtime.GOARCH == "arm64" {
+ return true, ""
+ }
}
+ return false, "unsupported arch"
case "syz_init_net_socket":
// Unfortunately this only works with sandbox none at the moment.
// The problem is that setns of a network namespace requires CAP_SYS_ADMIN
// in the target namespace, and we've lost all privs in the init namespace
// during creation of a user namespace.
if syscall.Getuid() != 0 || sandbox != "none" {
- return false
+ return false, "only supported under root with sandbox=none"
}
return isSupportedSocket(c)
case "syz_genetlink_get_family_id":
- fd, _ := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_GENERIC)
+ fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_GENERIC)
if fd == -1 {
- return false
+ return false, fmt.Sprintf("socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC) failed: %v", err)
}
syscall.Close(fd)
- return true
+ return true, ""
case "syz_mount_image":
- return sandbox != "setuid"
+ if syscall.Getuid() != 0 || sandbox == "setuid" {
+ return false, "only supported under root with sandbox=none/namespace"
+ }
+ return true, ""
case "syz_read_part_table":
- return sandbox == "none" && syscall.Getuid() == 0
+ if syscall.Getuid() != 0 || sandbox != "none" {
+ return false, "only supported under root with sandbox=none"
+ }
+ return true, ""
}
panic("unknown syzkall: " + c.Name)
}
-func isSupportedSocket(c *prog.Syscall) bool {
+func isSupportedSocket(c *prog.Syscall) (bool, string) {
af, ok := c.Args[0].(*prog.ConstType)
if !ok {
panic("socket family is not const")
@@ -154,19 +176,28 @@ func isSupportedSocket(c *prog.Syscall) bool {
if fd != -1 {
syscall.Close(fd)
}
- return err != syscall.ENOSYS && err != syscall.EAFNOSUPPORT
+ if err == syscall.ENOSYS {
+ return false, "socket syscall returns ENOSYS"
+ }
+ if err == syscall.EAFNOSUPPORT {
+ return false, "socket family is not supported (EAFNOSUPPORT)"
+ }
+ return true, ""
}
-func isSupportedOpenAt(c *prog.Syscall) bool {
+func isSupportedOpenAt(c *prog.Syscall) (bool, string) {
fname, ok := extractStringConst(c.Args[1])
if !ok || len(fname) == 0 || fname[0] != '/' {
- return true
+ return true, ""
}
fd, err := syscall.Open(fname, syscall.O_RDONLY, 0)
if fd != -1 {
syscall.Close(fd)
}
- return err == nil
+ if err != nil {
+ return false, fmt.Sprintf("open(%v) failed: %v", fname, err)
+ }
+ return true, ""
}
func extractStringConst(typ prog.Type) (string, bool) {
diff --git a/pkg/host/host_linux_test.go b/pkg/host/host_linux_test.go
index 9deda69bc..084428ab2 100644
--- a/pkg/host/host_linux_test.go
+++ b/pkg/host/host_linux_test.go
@@ -11,50 +11,15 @@ import (
"testing"
"github.com/google/syzkaller/prog"
- _ "github.com/google/syzkaller/sys"
)
-func TestLog(t *testing.T) {
- t.Parallel()
- target, err := prog.GetTarget("linux", runtime.GOARCH)
- if err != nil {
- t.Fatal(err)
- }
- // Dump for manual inspection.
- supp, err := DetectSupportedSyscalls(target, "none")
- if err != nil {
- t.Skipf("skipping: %v", err)
- }
- t.Logf("unsupported:")
- for _, c := range target.Syscalls {
- s, ok := supp[c]
- if ok && !s {
- t.Fatalf("map contains false value")
- }
- if !s {
- t.Logf("\t%v", c.Name)
- }
- }
- trans := target.TransitivelyEnabledCalls(supp)
- t.Logf("transitively unsupported:")
- for _, c := range target.Syscalls {
- s, ok := trans[c]
- if ok && !s {
- t.Fatalf("map contains false value")
- }
- if !s && supp[c] {
- t.Logf("\t%v", c.Name)
- }
- }
-}
-
func TestSupportedSyscalls(t *testing.T) {
t.Parallel()
target, err := prog.GetTarget("linux", runtime.GOARCH)
if err != nil {
t.Fatal(err)
}
- supp, err := DetectSupportedSyscalls(target, "none")
+ supp, _, err := DetectSupportedSyscalls(target, "none")
if err != nil {
t.Skipf("skipping: %v", err)
}
diff --git a/pkg/host/host_netbsd.go b/pkg/host/host_netbsd.go
index 39e8655c4..bada10ec7 100644
--- a/pkg/host/host_netbsd.go
+++ b/pkg/host/host_netbsd.go
@@ -7,13 +7,8 @@ import (
"github.com/google/syzkaller/prog"
)
-// DetectSupportedSyscalls returns list on supported syscalls on host.
-func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Syscall]bool, error) {
- supported := make(map[*prog.Syscall]bool)
- for _, c := range target.Syscalls {
- supported[c] = true
- }
- return supported, nil
+func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
+ return true, ""
}
func EnableFaultInjection() error {
diff --git a/pkg/host/host_test.go b/pkg/host/host_test.go
new file mode 100644
index 000000000..470a6e5e1
--- /dev/null
+++ b/pkg/host/host_test.go
@@ -0,0 +1,45 @@
+// Copyright 2015 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 host
+
+import (
+ "runtime"
+ "testing"
+
+ "github.com/google/syzkaller/prog"
+ _ "github.com/google/syzkaller/sys"
+)
+
+func TestLog(t *testing.T) {
+ t.Parallel()
+ target, err := prog.GetTarget(runtime.GOOS, runtime.GOARCH)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Dump for manual inspection.
+ supp, disabled, err := DetectSupportedSyscalls(target, "none")
+ if err != nil {
+ t.Skipf("skipping: %v", err)
+ }
+ for c, ok := range supp {
+ if !ok {
+ t.Fatalf("map contains false value for %v", c.Name)
+ }
+ }
+ t.Logf("unsupported:")
+ for c, reason := range disabled {
+ t.Logf("%v: %v", c.Name, reason)
+ }
+ trans := target.TransitivelyEnabledCalls(supp)
+ t.Logf("\n\ntransitively unsupported:")
+ for _, c := range target.Syscalls {
+ s, ok := trans[c]
+ if ok && !s {
+ t.Fatalf("map contains false value")
+ }
+ if !s && supp[c] {
+ t.Logf("%v", c.Name)
+ }
+ }
+}
diff --git a/pkg/host/host_windows.go b/pkg/host/host_windows.go
index 39e8655c4..bada10ec7 100644
--- a/pkg/host/host_windows.go
+++ b/pkg/host/host_windows.go
@@ -7,13 +7,8 @@ import (
"github.com/google/syzkaller/prog"
)
-// DetectSupportedSyscalls returns list on supported syscalls on host.
-func DetectSupportedSyscalls(target *prog.Target, sandbox string) (map[*prog.Syscall]bool, error) {
- supported := make(map[*prog.Syscall]bool)
- for _, c := range target.Syscalls {
- supported[c] = true
- }
- return supported, nil
+func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
+ return true, ""
}
func EnableFaultInjection() error {