aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/host/host_linux.go
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/host/host_linux.go
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/host/host_linux.go')
-rw-r--r--pkg/host/host_linux.go70
1 files changed, 57 insertions, 13 deletions
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) {