aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/host/host_linux.go
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@google.com>2019-01-04 19:56:16 +0100
committerDmitry Vyukov <dvyukov@google.com>2019-01-08 16:06:27 +0100
commitbaa5c8e247d411a8546a0a89733e0823aae5e47f (patch)
tree92fd0924dc0ea50642e0048224c38a46ee48b653 /pkg/host/host_linux.go
parent37dd2683f5ecf5e47787f68eebf9676b87b638bb (diff)
fuzzer: speed up syscall support detection
Right now syz-fuzzer does a search through /proc/kallsyms for each syscall to check whether it's supported. Do one search instead and save the results to a map. This speeds up syscall detection ~60 times when testing arm64 kernel on x86. Also add another search pattern for arm64 and add some logging.
Diffstat (limited to 'pkg/host/host_linux.go')
-rw-r--r--pkg/host/host_linux.go43
1 files changed, 31 insertions, 12 deletions
diff --git a/pkg/host/host_linux.go b/pkg/host/host_linux.go
index 3523605c7..eb792a70b 100644
--- a/pkg/host/host_linux.go
+++ b/pkg/host/host_linux.go
@@ -9,6 +9,7 @@ import (
"io/ioutil"
"os"
"os/exec"
+ "regexp"
"runtime"
"strconv"
"strings"
@@ -17,12 +18,14 @@ import (
"time"
"unsafe"
+ "github.com/google/syzkaller/pkg/log"
"github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys/linux"
)
-func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
+func isSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
+ log.Logf(2, "checking support for %v", c.Name)
if strings.HasPrefix(c.CallName, "syz_") {
return isSupportedSyzkall(sandbox, c)
}
@@ -52,23 +55,39 @@ func isSupported(c *prog.Syscall, sandbox string) (bool, string) {
// 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")
+ kallsyms, _ := ioutil.ReadFile("/proc/kallsyms")
+ if len(kallsyms) == 0 {
+ return
+ }
+ var re *regexp.Regexp
+ switch target.Arch {
+ case "386", "amd64":
+ re = regexp.MustCompile(` T (sys|ksys|__ia32|__x64)_([^\n]+)\n`)
+ case "arm64":
+ re = regexp.MustCompile(` T (sys|ksys|__arm64)_([^\n]+)\n`)
+ default:
+ panic("unsupported arch for kallsyms parsing")
+ }
+ matches := re.FindAllSubmatch(kallsyms, -1)
+ for _, m := range matches {
+ name := string(m[2])
+ log.Logf(2, "found in kallsyms: %v", name)
+ kallsymsSyscallSet[name] = true
+ }
})
- if !testFallback && len(kallsyms) != 0 {
- return isSupportedKallsyms(c)
+ if !testFallback && len(kallsymsSyscallSet) != 0 {
+ r, v := isSupportedKallsyms(c)
+ return r, v
}
return isSupportedTrial(c)
}
func isSupportedKallsyms(c *prog.Syscall) (bool, string) {
name := c.CallName
- if newname := kallsymsMap[name]; newname != "" {
+ if newname := kallsymsRenameMap[name]; newname != "" {
name = newname
}
- if !bytes.Contains(kallsyms, []byte(" T sys_"+name+"\n")) &&
- !bytes.Contains(kallsyms, []byte(" T ksys_"+name+"\n")) &&
- !bytes.Contains(kallsyms, []byte(" T __ia32_sys_"+name+"\n")) &&
- !bytes.Contains(kallsyms, []byte(" T __x64_sys_"+name+"\n")) {
+ if !kallsymsSyscallSet[name] {
return false, fmt.Sprintf("sys_%v is not present in /proc/kallsyms", name)
}
return true, ""
@@ -114,9 +133,9 @@ func init() {
// umount2 is renamed to umount in arch/x86/entry/syscalls/syscall_64.tbl.
// Where umount is renamed to oldumount is unclear.
var (
- kallsyms []byte
- kallsymsOnce sync.Once
- kallsymsMap = map[string]string{
+ kallsymsOnce sync.Once
+ kallsymsSyscallSet = make(map[string]bool)
+ kallsymsRenameMap = map[string]string{
"umount": "oldumount",
"umount2": "umount",
}