aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-06-18 19:45:45 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-06-18 19:45:45 +0200
commitaf9f337ea645491c9ec8db05d305887a51e419fe (patch)
tree5d4507d383e2bd2d476042d6e867f281f99a0516 /pkg
parent7bd97c6ff6472db1e2ad9f279fe517cd7b5daee2 (diff)
pkg/host: support trial supported syscall detection
Detect supported syscall by directly executing them if kallsyms is not present. This is required for gvisor testing.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/host/host.go2
-rw-r--r--pkg/host/host_linux.go70
-rw-r--r--pkg/host/host_test.go52
3 files changed, 89 insertions, 35 deletions
diff --git a/pkg/host/host.go b/pkg/host/host.go
index d4f4d71a8..2c300189e 100644
--- a/pkg/host/host.go
+++ b/pkg/host/host.go
@@ -27,6 +27,8 @@ func DetectSupportedSyscalls(target *prog.Target, sandbox string) (
return supported, unsupported, nil
}
+var testFallback = false
+
const (
FeatureCoverage = iota
FeatureComparisons
diff --git a/pkg/host/host_linux.go b/pkg/host/host_linux.go
index dff8bd88d..4b9f3ebe4 100644
--- a/pkg/host/host_linux.go
+++ b/pkg/host/host_linux.go
@@ -22,6 +22,16 @@ import (
)
func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
+ if strings.HasPrefix(c.CallName, "syz_") {
+ return isSupportedSyzkall(sandbox, c)
+ }
+ if strings.HasPrefix(c.Name, "socket$") ||
+ strings.HasPrefix(c.Name, "socketpair$") {
+ return isSupportedSocket(c)
+ }
+ if strings.HasPrefix(c.Name, "openat$") {
+ return isSupportedOpenAt(c)
+ }
// 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,
@@ -30,23 +40,19 @@ func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
// This requires root and CONFIG_FTRACE_SYSCALLS. Also it lies for some syscalls.
// 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.
+ // Requires CONFIG_KALLSYMS.
+ // Kallsyms seems to be the most reliable and fast. That's what we use first.
+ // If kallsyms is not present, we fallback to execution of syscalls.
kallsymsOnce.Do(func() {
kallsyms, _ = ioutil.ReadFile("/proc/kallsyms")
})
- if strings.HasPrefix(c.CallName, "syz_") {
- return isSupportedSyzkall(sandbox, c)
- }
- if strings.HasPrefix(c.Name, "socket$") ||
- strings.HasPrefix(c.Name, "socketpair$") {
- return isSupportedSocket(c)
- }
- if strings.HasPrefix(c.Name, "openat$") {
- return isSupportedOpenAt(c)
- }
- if len(kallsyms) == 0 {
- return true, ""
+ if !testFallback && len(kallsyms) != 0 {
+ return isSupportedKallsyms(c)
}
+ return isSupportedTrial(c)
+}
+
+func isSupportedKallsyms(c *prog.Syscall) (bool, string) {
name := c.CallName
if newname := kallsymsMap[name]; newname != "" {
name = newname
@@ -60,6 +66,42 @@ func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
return true, ""
}
+func isSupportedTrial(c *prog.Syscall) (bool, string) {
+ switch c.CallName {
+ // These known to cause hangs.
+ case "exit", "pause":
+ return true, ""
+ }
+ trialMu.Lock()
+ defer trialMu.Unlock()
+ if res, ok := trialSupported[c.NR]; ok {
+ return res, "ENOSYS"
+ }
+ cmd := osutil.Command(os.Args[0])
+ cmd.Env = []string{fmt.Sprintf("SYZ_TRIAL_TEST=%v", c.NR)}
+ _, err := osutil.Run(10*time.Second, cmd)
+ res := err != nil
+ trialSupported[c.NR] = res
+ return res, "ENOSYS"
+}
+
+func init() {
+ str := os.Getenv("SYZ_TRIAL_TEST")
+ if str == "" {
+ return
+ }
+ nr, err := strconv.Atoi(str)
+ if err != nil {
+ panic(err)
+ }
+ arg := ^uintptr(0) - 1e4 // something as invalid as possible
+ _, _, err = syscall.Syscall6(uintptr(nr), arg, arg, arg, arg, arg, arg)
+ if err == syscall.ENOSYS {
+ os.Exit(0)
+ }
+ os.Exit(1)
+}
+
// 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.
@@ -70,6 +112,8 @@ var (
"umount": "oldumount",
"umount2": "umount",
}
+ trialMu sync.Mutex
+ trialSupported = make(map[uint64]bool)
)
func isSupportedSyzkall(sandbox string, c *prog.Syscall) (bool, string) {
diff --git a/pkg/host/host_test.go b/pkg/host/host_test.go
index 8a16d5e5d..c44b9bbce 100644
--- a/pkg/host/host_test.go
+++ b/pkg/host/host_test.go
@@ -4,6 +4,7 @@
package host
import (
+ "fmt"
"runtime"
"testing"
@@ -13,28 +14,35 @@ import (
func TestDetectSupportedSyscalls(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)
- }
- _, disabled = target.TransitivelyEnabledCalls(supp)
- t.Logf("\n\ntransitively unsupported:")
- for c, reason := range disabled {
- t.Logf("%v: %v", c.Name, reason)
+ for _, fallback := range []bool{false, true} {
+ t.Run(fmt.Sprintf("fallback=%v", fallback), func(t *testing.T) {
+ oldFallback := testFallback
+ testFallback = fallback
+ defer func() { testFallback = oldFallback }()
+ 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.Fatal(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)
+ }
+ _, disabled = target.TransitivelyEnabledCalls(supp)
+ t.Logf("\n\ntransitively unsupported:")
+ for c, reason := range disabled {
+ t.Logf("%v: %v", c.Name, reason)
+ }
+ })
}
}