aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-09-25 08:47:15 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-09-25 08:47:48 +0200
commite9c477a5b3a05a614d9a0c68ba9724762a363784 (patch)
treea89fbfd6c3f8543f0b86a4c8c68c365a53a40ba1
parent8f8cf20bd23a37aaf4ac3a7ec3fab2370ef2a755 (diff)
sys/syz-extract: support fuchsia
-rw-r--r--Makefile6
-rw-r--r--docs/syscall_descriptions.md23
-rw-r--r--executor/syscalls_fuchsia.h4
-rw-r--r--pkg/compiler/compiler_test.go5
-rw-r--r--pkg/compiler/consts.go5
-rw-r--r--pkg/compiler/consts_test.go7
-rw-r--r--sys/fuchsia/amd64.go8
-rw-r--r--sys/fuchsia/arm64.go28
-rw-r--r--sys/fuchsia/sys.txt4
-rw-r--r--sys/fuchsia/sys_amd64.const28
-rw-r--r--sys/fuchsia/sys_arm64.const23
-rwxr-xr-xsys/linux/extract.sh46
-rw-r--r--sys/syz-extract/extract.go139
-rw-r--r--sys/syz-extract/fuchsia.go107
-rw-r--r--sys/syz-extract/linux.go (renamed from sys/syz-extract/fetch.go)81
15 files changed, 333 insertions, 181 deletions
diff --git a/Makefile b/Makefile
index a37c299ed..7727f155d 100644
--- a/Makefile
+++ b/Makefile
@@ -156,7 +156,7 @@ upgrade:
GOOS=$(HOSTOS) GOARCH=$(HOSTARCH) go build $(GOFLAGS) -o ./bin/syz-upgrade github.com/google/syzkaller/tools/syz-upgrade
extract: bin/syz-extract
- LINUX=$(LINUX) ./sys/linux/extract.sh
+ bin/syz-extract -build -os=$(TARGETOS) -sourcedir=$(SOURCEDIR)
bin/syz-extract:
go build $(GOFLAGS) -o $@ ./sys/syz-extract
@@ -208,3 +208,7 @@ presubmit:
clean:
rm -rf ./bin/
+
+# For a tupical Ubuntu/Debian distribution, requires sudo.
+install_prerequisites:
+ apt-get install libc6-dev-i386 lib32stdc++-4.8-dev linux-libc-dev g++-aarch64-linux-gnu g++-powerpc64le-linux-gnu g++-arm-linux-gnueabihf
diff --git a/docs/syscall_descriptions.md b/docs/syscall_descriptions.md
index 3fd5de919..a1ea560ae 100644
--- a/docs/syscall_descriptions.md
+++ b/docs/syscall_descriptions.md
@@ -10,8 +10,8 @@ close(fd fd)
open_mode = S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH
```
-The description is contained in `sys/*.txt` files.
-For example see the [sys/sys.txt](/sys/sys.txt) file.
+The description is contained in `sys/linux/*.txt` files.
+For example see the [sys/linux/sys.txt](/sys/linux/sys.txt) file.
## Syntax
@@ -25,11 +25,11 @@ The first step is extraction of values of symbolic constants from Linux sources
`syz-extract` generates a small C program that includes kernel headers referenced by `include` directives,
defines macros as specified by `define` directives and prints values of symbolic constants.
Results are stored in `.const` files, one per arch.
-For example, [sys/tty.txt](/sys/tty.txt) is translated into [sys/tty_amd64.const](/sys/tty_amd64.const).
+For example, [sys/linux/tty.txt](/sys/linux/tty.txt) is translated into [sys/linux/tty_amd64.const](/sys/linux/tty_amd64.const).
The second step is generation of Go code for syzkaller.
This step uses syscall descriptions and the const files generated during the first step.
-You can see a result in [sys/sys_amd64.go](/sys/sys_amd64.go) and in [executor/syscalls.h](/executor/syscalls.h).
+You can see a result in [sys/linux/amd64.go](/sys/linux/amd64.go) and in [executor/syscalls_linux.h](/executor/syscalls_linux.h).
## Describing new system calls
@@ -37,24 +37,23 @@ This section describes how to extend syzkaller to allow fuzz testing of a new sy
this is particularly useful for kernel developers who are proposing new system calls.
First, add a declarative description of the new system call to the appropriate file:
- - Various `sys/<subsystem>.txt` files hold system calls for particular kernel
+ - Various `sys/linux/<subsystem>.txt` files hold system calls for particular kernel
subsystems, for example `bpf` or `socket`.
- - [sys/sys.txt](/sys/sys.txt) holds descriptions for more general system calls.
- - An entirely new subsystem can be added as a new `sys/<new>.txt` file.
+ - [sys/linux/sys.txt](/sys/linux/sys.txt) holds descriptions for more general system calls.
+ - An entirely new subsystem can be added as a new `sys/linux/<new>.txt` file.
The description of the syntax can be found [here](syscall_descriptions_syntax.md).
-If the subsystem is present in the mainline kernel, add the new txt file to `sys/extract.sh` file
-and run `make extract LINUX=$KSRC` with `$KSRC` set to the location of a kernel source tree.
-This will generate const files.
+If the subsystem is present in the mainline kernel, run `make extract TARGETOS=linux SOURCEDIR=$KSRC`
+with `$KSRC` set to the location of a kernel source tree. This will generate const files.
Not, that this will overwrite `.config` file you have in `$KSRC`.
If the subsystem is not present in the mainline kernel, then you need to manually run `syz-extract` binary:
```
make bin/syz-extract
-bin/syz-extract -arch $ARCH -linux "$LINUX" -linuxbld "$LINUXBLD" sys/<new>.txt
+bin/syz-extract -os linux -arch $ARCH -sourcedir "$LINUX" -builddir "$LINUXBLD" <new>.txt
```
-`$ARCH` is one of `amd64`, `arm64`, `ppc64le`.
+`$ARCH` is one of `amd64`, `386` `arm64`, `arm`, `ppc64le`.
If the subsystem is supported on several architectures, then run `syz-extract` for each arch.
`$LINUX` should point to kernel source checkout, which is configured for the corresponding arch (i.e. you need to run `make someconfig && make` there first).
If the kernel was built into a separate directory (with `make O=...`) then also set `$LINUXBLD` to the location of the build directory.
diff --git a/executor/syscalls_fuchsia.h b/executor/syscalls_fuchsia.h
index f64ef023c..7d4eb574b 100644
--- a/executor/syscalls_fuchsia.h
+++ b/executor/syscalls_fuchsia.h
@@ -2,7 +2,7 @@
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
-#define SYZ_REVISION "640bc9ab193d2488d41793c10c5a44bab3ad33f9"
+#define SYZ_REVISION "9b1c1a07ba105b616c1fb926256ea6a00b57b664"
#define __NR_syz_mmap 1000000
unsigned syscall_count = 5;
@@ -18,7 +18,7 @@ call_t syscalls[] = {
#if defined(__aarch64__) || 0
#define GOARCH "arm64"
-#define SYZ_REVISION "8c364809f3ccf951f9c9ac974a817dfaf8d1713c"
+#define SYZ_REVISION "9e985d79861e2754a6fead2a7c97ca4854e3df44"
#define __NR_syz_mmap 1000000
unsigned syscall_count = 5;
diff --git a/pkg/compiler/compiler_test.go b/pkg/compiler/compiler_test.go
index be803bae9..ac2d88167 100644
--- a/pkg/compiler/compiler_test.go
+++ b/pkg/compiler/compiler_test.go
@@ -38,6 +38,7 @@ func TestErrors(t *testing.T) {
"C1": 1,
"C2": 2,
}
+ target := targets.List["linux"]["amd64"]
for _, name := range []string{"errors.txt", "errors2.txt"} {
name := name
t.Run(name, func(t *testing.T) {
@@ -47,8 +48,8 @@ func TestErrors(t *testing.T) {
em.DumpErrors(t)
t.Fatalf("parsing failed")
}
- ExtractConsts(desc, em.ErrorHandler)
- Compile(desc, consts, targets.List["linux"]["amd64"], em.ErrorHandler)
+ ExtractConsts(desc, target, em.ErrorHandler)
+ Compile(desc, consts, target, em.ErrorHandler)
em.Check(t)
})
}
diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go
index 4cb68e773..c2051ab5d 100644
--- a/pkg/compiler/consts.go
+++ b/pkg/compiler/consts.go
@@ -25,7 +25,7 @@ type ConstInfo struct {
}
// ExtractConsts returns list of literal constants and other info required const value extraction.
-func ExtractConsts(desc *ast.Description, eh0 ast.ErrorHandler) *ConstInfo {
+func ExtractConsts(desc *ast.Description, target *targets.Target, eh0 ast.ErrorHandler) *ConstInfo {
errors := 0
eh := func(pos ast.Pos, msg string, args ...interface{}) {
errors++
@@ -42,6 +42,7 @@ func ExtractConsts(desc *ast.Description, eh0 ast.ErrorHandler) *ConstInfo {
includeMap := make(map[string]bool)
incdirMap := make(map[string]bool)
constMap := make(map[string]bool)
+ syscallNumbers := targets.OSList[target.OS].SyscallNumbers
ast.Walk(desc, func(n1 ast.Node) {
switch n := n1.(type) {
@@ -74,7 +75,7 @@ func ExtractConsts(desc *ast.Description, eh0 ast.ErrorHandler) *ConstInfo {
info.Defines[name] = v
constMap[name] = true
case *ast.Call:
- if !strings.HasPrefix(n.CallName, "syz_") {
+ if syscallNumbers && !strings.HasPrefix(n.CallName, "syz_") {
constMap["__NR_"+n.CallName] = true
}
case *ast.Type:
diff --git a/pkg/compiler/consts_test.go b/pkg/compiler/consts_test.go
index 647b2f1f4..918f61d0c 100644
--- a/pkg/compiler/consts_test.go
+++ b/pkg/compiler/consts_test.go
@@ -10,6 +10,7 @@ import (
"testing"
"github.com/google/syzkaller/pkg/ast"
+ "github.com/google/syzkaller/sys/targets"
)
func TestExtractConsts(t *testing.T) {
@@ -21,7 +22,8 @@ func TestExtractConsts(t *testing.T) {
if desc == nil {
t.Fatalf("failed to parse input")
}
- info := ExtractConsts(desc, func(pos ast.Pos, msg string) {
+ target := targets.List["linux"]["amd64"]
+ info := ExtractConsts(desc, target, func(pos ast.Pos, msg string) {
t.Fatalf("%v: %v", pos, msg)
})
wantConsts := []string{"CONST1", "CONST10", "CONST11", "CONST12", "CONST13",
@@ -56,6 +58,7 @@ func TestConstErrors(t *testing.T) {
em.DumpErrors(t)
t.Fatalf("parsing failed")
}
- ExtractConsts(desc, em.ErrorHandler)
+ target := targets.List["linux"]["amd64"]
+ ExtractConsts(desc, target, em.ErrorHandler)
em.Check(t)
}
diff --git a/sys/fuchsia/amd64.go b/sys/fuchsia/amd64.go
index 8331d756d..738bcc71e 100644
--- a/sys/fuchsia/amd64.go
+++ b/sys/fuchsia/amd64.go
@@ -37,9 +37,9 @@ var syscalls_amd64 = []*Syscall{
}
var consts_amd64 = []ConstValue{
- {Name: "MX_CLOCK_MONOTONIC"},
- {Name: "MX_CLOCK_THREAD", Value: 2},
- {Name: "MX_CLOCK_UTC", Value: 1},
+ {Name: "ZX_CLOCK_MONOTONIC"},
+ {Name: "ZX_CLOCK_THREAD", Value: 2},
+ {Name: "ZX_CLOCK_UTC", Value: 1},
{Name: "ZX_RIGHT_DESTROY", Value: 512},
{Name: "ZX_RIGHT_DUPLICATE", Value: 1},
{Name: "ZX_RIGHT_ENUMERATE", Value: 256},
@@ -58,4 +58,4 @@ var consts_amd64 = []ConstValue{
{Name: "ZX_RIGHT_WRITE", Value: 8},
}
-const revision_amd64 = "640bc9ab193d2488d41793c10c5a44bab3ad33f9"
+const revision_amd64 = "9b1c1a07ba105b616c1fb926256ea6a00b57b664"
diff --git a/sys/fuchsia/arm64.go b/sys/fuchsia/arm64.go
index 1341b864c..28bdb5b54 100644
--- a/sys/fuchsia/arm64.go
+++ b/sys/fuchsia/arm64.go
@@ -23,12 +23,12 @@ var syscalls_arm64 = []*Syscall{
}},
{ID: 2, Name: "zx_handle_duplicate", CallName: "zx_handle_duplicate", Args: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "zx_handle", FldName: "handle", TypeSize: 4}},
- &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "zx_rights", FldName: "rights", TypeSize: 8}}},
+ &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "zx_rights", FldName: "rights", TypeSize: 8}}, Vals: []uint64{0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 2147483648}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "out", TypeSize: 8}, Type: &ResourceType{TypeCommon: TypeCommon{TypeName: "zx_handle", TypeSize: 4, ArgDir: 1}}},
}},
{ID: 3, Name: "zx_handle_replace", CallName: "zx_handle_replace", Args: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "zx_handle", FldName: "handle", TypeSize: 4}},
- &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "zx_rights", FldName: "rights", TypeSize: 8}}},
+ &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "zx_rights", FldName: "rights", TypeSize: 8}}, Vals: []uint64{0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 2147483648}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "out", TypeSize: 8}, Type: &ResourceType{TypeCommon: TypeCommon{TypeName: "zx_handle", TypeSize: 4, ArgDir: 1}}},
}},
{ID: 4, Name: "zx_time_get", CallName: "zx_time_get", Args: []Type{
@@ -37,9 +37,25 @@ var syscalls_arm64 = []*Syscall{
}
var consts_arm64 = []ConstValue{
- {Name: "MX_CLOCK_MONOTONIC"},
- {Name: "MX_CLOCK_THREAD", Value: 2},
- {Name: "MX_CLOCK_UTC", Value: 1},
+ {Name: "ZX_CLOCK_MONOTONIC"},
+ {Name: "ZX_CLOCK_THREAD", Value: 2},
+ {Name: "ZX_CLOCK_UTC", Value: 1},
+ {Name: "ZX_RIGHT_DESTROY", Value: 512},
+ {Name: "ZX_RIGHT_DUPLICATE", Value: 1},
+ {Name: "ZX_RIGHT_ENUMERATE", Value: 256},
+ {Name: "ZX_RIGHT_EXECUTE", Value: 16},
+ {Name: "ZX_RIGHT_GET_POLICY", Value: 2048},
+ {Name: "ZX_RIGHT_GET_PROPERTY", Value: 64},
+ {Name: "ZX_RIGHT_MAP", Value: 32},
+ {Name: "ZX_RIGHT_NONE"},
+ {Name: "ZX_RIGHT_READ", Value: 4},
+ {Name: "ZX_RIGHT_SAME_RIGHTS", Value: 2147483648},
+ {Name: "ZX_RIGHT_SET_POLICY", Value: 1024},
+ {Name: "ZX_RIGHT_SET_PROPERTY", Value: 128},
+ {Name: "ZX_RIGHT_SIGNAL", Value: 4096},
+ {Name: "ZX_RIGHT_SIGNAL_PEER", Value: 8192},
+ {Name: "ZX_RIGHT_TRANSFER", Value: 2},
+ {Name: "ZX_RIGHT_WRITE", Value: 8},
}
-const revision_arm64 = "8c364809f3ccf951f9c9ac974a817dfaf8d1713c"
+const revision_arm64 = "9e985d79861e2754a6fead2a7c97ca4854e3df44"
diff --git a/sys/fuchsia/sys.txt b/sys/fuchsia/sys.txt
index 0da424b97..383246323 100644
--- a/sys/fuchsia/sys.txt
+++ b/sys/fuchsia/sys.txt
@@ -1,6 +1,8 @@
# Copyright 2017 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.
+include <zircon/syscalls.h>
+
syz_mmap(addr vma, len len[addr])
resource zx_handle[int32]: 0
@@ -11,6 +13,6 @@ zx_handle_replace(handle zx_handle, rights flags[zx_rights], out ptr[out, zx_han
zx_time_get(clock_id flags[clock_id])
-clock_id = MX_CLOCK_MONOTONIC, MX_CLOCK_UTC, MX_CLOCK_THREAD
+clock_id = ZX_CLOCK_MONOTONIC, ZX_CLOCK_UTC, ZX_CLOCK_THREAD
zx_rights = ZX_RIGHT_NONE, ZX_RIGHT_DUPLICATE, ZX_RIGHT_TRANSFER, ZX_RIGHT_READ, ZX_RIGHT_WRITE, ZX_RIGHT_EXECUTE, ZX_RIGHT_MAP, ZX_RIGHT_GET_PROPERTY, ZX_RIGHT_SET_PROPERTY, ZX_RIGHT_ENUMERATE, ZX_RIGHT_DESTROY, ZX_RIGHT_SET_POLICY, ZX_RIGHT_GET_POLICY, ZX_RIGHT_SIGNAL, ZX_RIGHT_SIGNAL_PEER, ZX_RIGHT_SAME_RIGHTS
diff --git a/sys/fuchsia/sys_amd64.const b/sys/fuchsia/sys_amd64.const
index c65545df9..e0496bf8c 100644
--- a/sys/fuchsia/sys_amd64.const
+++ b/sys/fuchsia/sys_amd64.const
@@ -1,20 +1,20 @@
-MX_CLOCK_MONOTONIC = 0
-MX_CLOCK_UTC = 1
-MX_CLOCK_THREAD = 2
-
-ZX_RIGHT_NONE = 0
+# AUTOGENERATED FILE
+ZX_CLOCK_MONOTONIC = 0
+ZX_CLOCK_THREAD = 2
+ZX_CLOCK_UTC = 1
+ZX_RIGHT_DESTROY = 512
ZX_RIGHT_DUPLICATE = 1
-ZX_RIGHT_TRANSFER = 2
-ZX_RIGHT_READ = 4
-ZX_RIGHT_WRITE = 8
+ZX_RIGHT_ENUMERATE = 256
ZX_RIGHT_EXECUTE = 16
-ZX_RIGHT_MAP = 32
+ZX_RIGHT_GET_POLICY = 2048
ZX_RIGHT_GET_PROPERTY = 64
-ZX_RIGHT_SET_PROPERTY = 128
-ZX_RIGHT_ENUMERATE = 256
-ZX_RIGHT_DESTROY = 512
+ZX_RIGHT_MAP = 32
+ZX_RIGHT_NONE = 0
+ZX_RIGHT_READ = 4
+ZX_RIGHT_SAME_RIGHTS = 2147483648
ZX_RIGHT_SET_POLICY = 1024
-ZX_RIGHT_GET_POLICY = 2048
+ZX_RIGHT_SET_PROPERTY = 128
ZX_RIGHT_SIGNAL = 4096
ZX_RIGHT_SIGNAL_PEER = 8192
-ZX_RIGHT_SAME_RIGHTS = 2147483648
+ZX_RIGHT_TRANSFER = 2
+ZX_RIGHT_WRITE = 8
diff --git a/sys/fuchsia/sys_arm64.const b/sys/fuchsia/sys_arm64.const
index caae81d94..e0496bf8c 100644
--- a/sys/fuchsia/sys_arm64.const
+++ b/sys/fuchsia/sys_arm64.const
@@ -1,3 +1,20 @@
-MX_CLOCK_MONOTONIC = 0
-MX_CLOCK_UTC = 1
-MX_CLOCK_THREAD = 2
+# AUTOGENERATED FILE
+ZX_CLOCK_MONOTONIC = 0
+ZX_CLOCK_THREAD = 2
+ZX_CLOCK_UTC = 1
+ZX_RIGHT_DESTROY = 512
+ZX_RIGHT_DUPLICATE = 1
+ZX_RIGHT_ENUMERATE = 256
+ZX_RIGHT_EXECUTE = 16
+ZX_RIGHT_GET_POLICY = 2048
+ZX_RIGHT_GET_PROPERTY = 64
+ZX_RIGHT_MAP = 32
+ZX_RIGHT_NONE = 0
+ZX_RIGHT_READ = 4
+ZX_RIGHT_SAME_RIGHTS = 2147483648
+ZX_RIGHT_SET_POLICY = 1024
+ZX_RIGHT_SET_PROPERTY = 128
+ZX_RIGHT_SIGNAL = 4096
+ZX_RIGHT_SIGNAL_PEER = 8192
+ZX_RIGHT_TRANSFER = 2
+ZX_RIGHT_WRITE = 8
diff --git a/sys/linux/extract.sh b/sys/linux/extract.sh
deleted file mode 100755
index e6dc9e880..000000000
--- a/sys/linux/extract.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-# Assuming x86 host, you also need to install:
-# sudo apt-get install gcc-aarch64-linux-gnu gcc-powerpc64le-linux-gnu gcc-arm-linux-gnueabihf
-
-set -eu
-
-if [ "$LINUX" == "" ]; then
- if [ "$ANDROID" == "" ]; then
- echo "usage: make extract LINUX=/linux/checkout]"
- echo "OR: make extract ANDROID=/linux/checkout]"
- exit 1
- else
- LINUX=$ANDROID
- BUILD_FOR_ANDROID=yes
- fi
-else
- BUILD_FOR_ANDROID=no
-fi
-
-UPSTREAM_FILES="bpf.txt dri.txt fuse.txt input.txt ipc.txt
- key.txt kvm.txt loop.txt perf.txt random.txt
- sndcontrol.txt sndseq.txt sndtimer.txt
- sys.txt test.txt tty.txt tun.txt vnet.txt
- socket.txt socket_alg.txt socket_bluetooth.txt
- socket_inet.txt socket_inet6.txt socket_inet_tcp.txt
- socket_inet_udp.txt socket_inet_icmp.txt
- socket_inet_sctp.txt socket_inet_dccp.txt
- socket_kcm.txt socket_key.txt socket_netlink.txt
- socket_netrom.txt socket_nfc.txt socket_unix.txt
- socket_ipx.txt socket_ax25.txt socket_llc.txt
- socket_packet.txt xattr.txt"
-
-ANDROID_FILES="tlk_device.txt ion.txt"
-
-if [ "$BUILD_FOR_ANDROID" == "no" ]; then
- ARCHES=""
- FILES="$UPSTREAM_FILES"
-else
- ARCHES="amd64,arm64"
- FILES="$ANDROID_FILES"
-fi
-
-(cd sys/linux; ../../bin/syz-extract -build -arch "$ARCHES" -linux "$LINUX" $FILES)
diff --git a/sys/syz-extract/extract.go b/sys/syz-extract/extract.go
index 764dcb0da..6820363db 100644
--- a/sys/syz-extract/extract.go
+++ b/sys/syz-extract/extract.go
@@ -14,7 +14,6 @@ import (
"sort"
"strings"
"sync"
- "time"
"github.com/google/syzkaller/pkg/ast"
"github.com/google/syzkaller/pkg/compiler"
@@ -23,15 +22,16 @@ import (
)
var (
- flagLinux = flag.String("linux", "", "path to linux kernel source checkout")
- flagLinuxBld = flag.String("linuxbld", "", "path to linux kernel build directory")
- flagArch = flag.String("arch", "", "comma-separated list of arches to generate (all by default)")
- flagBuild = flag.Bool("build", false, "regenerate arch-specific kernel headers")
+ flagOS = flag.String("os", "", "target OS")
+ flagBuild = flag.Bool("build", false, "regenerate arch-specific kernel headers")
+ flagSourceDir = flag.String("sourcedir", "", "path to kernel source checkout dir")
+ flagBuildDir = flag.String("builddir", "", "path to kernel build dir")
+ flagArch = flag.String("arch", "", "comma-separated list of arches to generate (all by default)")
)
type Arch struct {
target *targets.Target
- kernelDir string
+ sourceDir string
buildDir string
build bool
files []*File
@@ -45,49 +45,75 @@ type File struct {
err error
}
+type OS interface {
+ prepare(sourcedir string, build bool, arches []string) error
+ prepareArch(arch *Arch) error
+ processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error)
+}
+
+var oses = map[string]OS{
+ "linux": new(linux),
+ "android": new(linux),
+ "fuchsia": new(fuchsia),
+}
+
func main() {
failf := func(msg string, args ...interface{}) {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
os.Exit(1)
}
-
- const OS = "linux"
flag.Parse()
- if *flagLinux == "" {
- failf("provide path to linux kernel checkout via -linux flag (or make extract LINUX= flag)")
+
+ OS := oses[*flagOS]
+ if OS == nil {
+ failf("unknown os: %v", *flagOS)
}
- if *flagBuild && *flagLinuxBld != "" {
- failf("-build and -linuxbld is an invalid combination")
+ if *flagSourceDir == "" {
+ failf("provide path to kernel checkout via -sourcedir flag (or make extract SOURCEDIR)")
}
- n := len(flag.Args())
- if n == 0 {
- failf("usage: syz-extract -linux=/linux/checkout -arch=arch input_file.txt...")
+ if *flagBuild && *flagBuildDir != "" {
+ failf("-build and -builddir is an invalid combination")
}
-
var archArray []string
if *flagArch != "" {
archArray = strings.Split(*flagArch, ",")
} else {
- for arch := range targets.List[OS] {
+ for arch := range targets.List[*flagOS] {
archArray = append(archArray, arch)
}
+ if *flagOS == "android" {
+ archArray = []string{"amd64", "arm64"}
+ }
sort.Strings(archArray)
}
-
- if *flagBuild {
- // Otherwise out-of-tree build fails.
- fmt.Printf("make mrproper\n")
- out, err := osutil.RunCmd(time.Hour, *flagLinux, "make", "mrproper")
- if err != nil {
- failf("make mrproper failed: %v\n%s\n", err, out)
+ files := flag.Args()
+ if len(files) == 0 {
+ matches, err := filepath.Glob(filepath.Join("sys", *flagOS, "*.txt"))
+ if err != nil || len(matches) == 0 {
+ failf("failed to find sys files: %v", err)
}
- } else {
- if len(archArray) > 1 {
- failf("more than 1 arch is invalid without -build")
+ androidFiles := map[string]bool{
+ "ion.txt": true,
+ "tlk_device.txt": true,
+ }
+ for _, f := range matches {
+ f = filepath.Base(f)
+ if *flagOS == "linux" && androidFiles[f] {
+ continue
+ }
+ if *flagOS == "android" && !androidFiles[f] {
+ continue
+ }
+ files = append(files, filepath.Base(f))
}
+ sort.Strings(files)
}
- jobC := make(chan interface{}, len(archArray)*len(flag.Args()))
+ if err := OS.prepare(*flagSourceDir, *flagBuild, archArray); err != nil {
+ failf("%v", err)
+ }
+
+ jobC := make(chan interface{}, len(archArray)*len(files))
var wg sync.WaitGroup
var arches []*Arch
@@ -99,24 +125,24 @@ func main() {
failf("failed to create temp dir: %v", err)
}
buildDir = dir
- } else if *flagLinuxBld != "" {
- buildDir = *flagLinuxBld
+ } else if *flagBuildDir != "" {
+ buildDir = *flagBuildDir
} else {
- buildDir = *flagLinux
+ buildDir = *flagSourceDir
}
- target := targets.List[OS][archStr]
+ target := targets.List[*flagOS][archStr]
if target == nil {
failf("unknown arch: %v", archStr)
}
arch := &Arch{
target: target,
- kernelDir: *flagLinux,
+ sourceDir: *flagSourceDir,
buildDir: buildDir,
build: *flagBuild,
}
- for _, f := range flag.Args() {
+ for _, f := range files {
arch.files = append(arch.files, &File{
arch: arch,
name: f,
@@ -132,9 +158,7 @@ func main() {
for job := range jobC {
switch j := job.(type) {
case *Arch:
- if j.build {
- j.err = buildKernel(j)
- }
+ j.err = OS.prepareArch(j)
if j.err == nil {
for _, f := range j.files {
wg.Add(1)
@@ -142,7 +166,7 @@ func main() {
}
}
case *File:
- j.undeclared, j.err = processFile(j.arch, j.name)
+ j.undeclared, j.err = processFile(OS, j.arch, j.name)
}
wg.Done()
}
@@ -174,7 +198,8 @@ func main() {
}
}
-func processFile(arch *Arch, inname string) (map[string]bool, error) {
+func processFile(OS OS, arch *Arch, inname string) (map[string]bool, error) {
+ inname = filepath.Join("sys", arch.target.OS, inname)
outname := strings.TrimSuffix(inname, ".txt") + "_" + arch.target.Arch + ".const"
indata, err := ioutil.ReadFile(inname)
if err != nil {
@@ -188,15 +213,14 @@ func processFile(arch *Arch, inname string) (map[string]bool, error) {
if desc == nil {
return nil, fmt.Errorf("%v", errBuf.String())
}
- info := compiler.ExtractConsts(desc, eh)
+ info := compiler.ExtractConsts(desc, arch.target, eh)
if info == nil {
return nil, fmt.Errorf("%v", errBuf.String())
}
if len(info.Consts) == 0 {
return nil, nil
}
- includes := append(info.Includes, "asm/unistd.h")
- consts, undeclared, err := fetchValues(arch.target, arch.kernelDir, arch.buildDir, info.Consts, includes, info.Incdirs, info.Defines)
+ consts, undeclared, err := OS.processFile(arch, info)
if err != nil {
return nil, err
}
@@ -206,34 +230,3 @@ func processFile(arch *Arch, inname string) (map[string]bool, error) {
}
return undeclared, nil
}
-
-func buildKernel(arch *Arch) error {
- target := arch.target
- kernelDir := arch.kernelDir
- buildDir := arch.buildDir
- makeArgs := []string{
- "ARCH=" + target.KernelArch,
- "CROSS_COMPILE=" + target.CCompilerPrefix,
- "CFLAGS=" + strings.Join(target.CrossCFlags, " "),
- "O=" + buildDir,
- }
- out, err := osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "defconfig")...)
- if err != nil {
- return fmt.Errorf("make defconfig failed: %v\n%s\n", err, out)
- }
- // Without CONFIG_NETFILTER kernel does not build.
- out, err = osutil.RunCmd(time.Minute, buildDir, "sed", "-i",
- "s@# CONFIG_NETFILTER is not set@CONFIG_NETFILTER=y@g", ".config")
- if err != nil {
- return fmt.Errorf("sed .config failed: %v\n%s\n", err, out)
- }
- out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "olddefconfig")...)
- if err != nil {
- return fmt.Errorf("make olddefconfig failed: %v\n%s\n", err, out)
- }
- out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "init/main.o")...)
- if err != nil {
- return fmt.Errorf("make failed: %v\n%s\n", err, out)
- }
- return nil
-}
diff --git a/sys/syz-extract/fuchsia.go b/sys/syz-extract/fuchsia.go
new file mode 100644
index 000000000..1d3405ba8
--- /dev/null
+++ b/sys/syz-extract/fuchsia.go
@@ -0,0 +1,107 @@
+// Copyright 2017 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 main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/google/syzkaller/pkg/compiler"
+)
+
+type fuchsia struct{}
+
+func (*fuchsia) prepare(sourcedir string, build bool, arches []string) error {
+ return nil
+}
+
+func (*fuchsia) prepareArch(arch *Arch) error {
+ return nil
+}
+
+func (*fuchsia) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error) {
+ bin, out, err := fuchsiaCompile(arch.sourceDir, info.Consts, info.Includes, info.Incdirs, info.Defines)
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to run compiler: %v\n%v", err, string(out))
+ }
+ defer os.Remove(bin)
+
+ out, err = exec.Command(bin).CombinedOutput()
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to run compiled binary: %v\n%v", err, string(out))
+ }
+
+ flagVals := strings.Split(string(out), " ")
+ if len(out) == 0 {
+ flagVals = nil
+ }
+ if len(flagVals) != len(info.Consts) {
+ return nil, nil, fmt.Errorf("fetched wrong number of values %v, want %v", len(flagVals), len(info.Consts))
+ }
+ res := make(map[string]uint64)
+ for i, v := range flagVals {
+ n, err := strconv.ParseUint(v, 10, 64)
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to parse value: %v (%v)", err, v)
+ }
+ res[info.Consts[i]] = n
+ }
+ return res, nil, nil
+}
+
+func fuchsiaCompile(sourceDir string, vals, includes, incdirs []string, defines map[string]string) (bin string, out []byte, err error) {
+ includeText := ""
+ for _, inc := range includes {
+ includeText += fmt.Sprintf("#include <%v>\n", inc)
+ }
+ definesText := ""
+ for k, v := range defines {
+ definesText += fmt.Sprintf("#ifndef %v\n#define %v %v\n#endif\n", k, k, v)
+ }
+ valsText := strings.Join(vals, ",")
+ src := fuchsiaSrc
+ src = strings.Replace(src, "[[INCLUDES]]", includeText, 1)
+ src = strings.Replace(src, "[[DEFAULTS]]", definesText, 1)
+ src = strings.Replace(src, "[[VALS]]", valsText, 1)
+ binFile, err := ioutil.TempFile("", "")
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to create temp file: %v", err)
+ }
+ binFile.Close()
+ compiler := filepath.Join(sourceDir, "buildtools", "linux-x64", "clang", "bin", "clang")
+ includeDir := filepath.Join(sourceDir, "out", "build-zircon", "build-zircon-pc-x86-64", "sysroot", "include")
+ args := []string{"-x", "c", "-", "-o", binFile.Name(), "-fmessage-length=0", "-w", "-I", includeDir}
+ for _, incdir := range incdirs {
+ args = append(args, "-I"+sourceDir+"/"+incdir)
+ }
+ cmd := exec.Command(compiler, args...)
+ cmd.Stdin = strings.NewReader(src)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ os.Remove(binFile.Name())
+ return "", out, err
+ }
+ return binFile.Name(), nil, nil
+}
+
+var fuchsiaSrc = `
+[[INCLUDES]]
+[[DEFAULTS]]
+int printf(const char *format, ...);
+int main() {
+ int i;
+ unsigned long long vals[] = {[[VALS]]};
+ for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
+ if (i != 0)
+ printf(" ");
+ printf("%llu", vals[i]);
+ }
+ return 0;
+}
+`
diff --git a/sys/syz-extract/fetch.go b/sys/syz-extract/linux.go
index 4fcbbcda5..8c38c75ee 100644
--- a/sys/syz-extract/fetch.go
+++ b/sys/syz-extract/linux.go
@@ -1,4 +1,4 @@
-// Copyright 2015 syzkaller project authors. All rights reserved.
+// Copyright 2017 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 main
@@ -11,17 +11,70 @@ import (
"regexp"
"strconv"
"strings"
+ "time"
+ "github.com/google/syzkaller/pkg/compiler"
+ "github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/sys/targets"
)
-// fetchValues converts literal constants (e.g. O_APPEND) or any other C expressions
-// into their respective numeric values. It does so by builting and executing a C program
-// that prints values of the provided expressions.
-func fetchValues(target *targets.Target, kernelDir, buildDir string,
- vals, includes, incdirs []string, defines map[string]string) (
- map[string]uint64, map[string]bool, error) {
- bin, out, err := runCompiler(target, kernelDir, buildDir, nil, includes, incdirs, nil, nil)
+type linux struct{}
+
+func (*linux) prepare(sourcedir string, build bool, arches []string) error {
+ if build {
+ // Otherwise out-of-tree build fails.
+ fmt.Printf("make mrproper\n")
+ out, err := osutil.RunCmd(time.Hour, sourcedir, "make", "mrproper")
+ if err != nil {
+ return fmt.Errorf("make mrproper failed: %v\n%s\n", err, out)
+ }
+ } else {
+ if len(arches) > 1 {
+ return fmt.Errorf("more than 1 arch is invalid without -build")
+ }
+ }
+ return nil
+}
+
+func (*linux) prepareArch(arch *Arch) error {
+ if !arch.build {
+ return nil
+ }
+ target := arch.target
+ kernelDir := arch.sourceDir
+ buildDir := arch.buildDir
+ makeArgs := []string{
+ "ARCH=" + target.KernelArch,
+ "CROSS_COMPILE=" + target.CCompilerPrefix,
+ "CFLAGS=" + strings.Join(target.CrossCFlags, " "),
+ "O=" + buildDir,
+ }
+ out, err := osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "defconfig")...)
+ if err != nil {
+ return fmt.Errorf("make defconfig failed: %v\n%s\n", err, out)
+ }
+ // Without CONFIG_NETFILTER kernel does not build.
+ out, err = osutil.RunCmd(time.Minute, buildDir, "sed", "-i",
+ "s@# CONFIG_NETFILTER is not set@CONFIG_NETFILTER=y@g", ".config")
+ if err != nil {
+ return fmt.Errorf("sed .config failed: %v\n%s\n", err, out)
+ }
+ out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "olddefconfig")...)
+ if err != nil {
+ return fmt.Errorf("make olddefconfig failed: %v\n%s\n", err, out)
+ }
+ out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "init/main.o")...)
+ if err != nil {
+ return fmt.Errorf("make failed: %v\n%s\n", err, out)
+ }
+ return nil
+}
+
+func (*linux) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error) {
+ vals := info.Consts
+ includes := append(info.Includes, "asm/unistd.h")
+ bin, out, err := linuxCompile(arch.target, arch.sourceDir, arch.buildDir, nil,
+ includes, info.Incdirs, nil, nil)
if err != nil {
return nil, nil, fmt.Errorf("failed to run gcc: %v\n%v", err, string(out))
}
@@ -33,7 +86,8 @@ func fetchValues(target *targets.Target, kernelDir, buildDir string,
}
undeclared := make(map[string]bool)
- bin, out, err = runCompiler(target, kernelDir, buildDir, vals, includes, incdirs, defines, undeclared)
+ bin, out, err = linuxCompile(arch.target, arch.sourceDir, arch.buildDir, vals,
+ includes, info.Incdirs, info.Defines, undeclared)
if err != nil {
for _, errMsg := range []string{
"error: ‘([a-zA-Z0-9_]+)’ undeclared",
@@ -48,7 +102,8 @@ func fetchValues(target *targets.Target, kernelDir, buildDir string,
}
}
}
- bin, out, err = runCompiler(target, kernelDir, buildDir, vals, includes, incdirs, defines, undeclared)
+ bin, out, err = linuxCompile(arch.target, arch.sourceDir, arch.buildDir, vals,
+ includes, info.Incdirs, info.Defines, undeclared)
if err != nil {
return nil, nil, fmt.Errorf("failed to run gcc: %v\n%v", err, string(out))
}
@@ -87,7 +142,7 @@ func fetchValues(target *targets.Target, kernelDir, buildDir string,
return res, undeclared, nil
}
-func runCompiler(target *targets.Target, kernelDir, buildDir string, vals, includes, incdirs []string, defines map[string]string, undeclared map[string]bool) (bin string, out []byte, err error) {
+func linuxCompile(target *targets.Target, kernelDir, buildDir string, vals, includes, incdirs []string, defines map[string]string, undeclared map[string]bool) (bin string, out []byte, err error) {
includeText := ""
for _, inc := range includes {
includeText += fmt.Sprintf("#include <%v>\n", inc)
@@ -106,7 +161,7 @@ func runCompiler(target *targets.Target, kernelDir, buildDir string, vals, inclu
}
valsText += v
}
- src := strings.Replace(fetchSrc, "[[INCLUDES]]", includeText, 1)
+ src := strings.Replace(linuxSrc, "[[INCLUDES]]", includeText, 1)
src = strings.Replace(src, "[[DEFAULTS]]", definesText, 1)
src = strings.Replace(src, "[[VALS]]", valsText, 1)
binFile, err := ioutil.TempFile("", "")
@@ -152,7 +207,7 @@ func runCompiler(target *targets.Target, kernelDir, buildDir string, vals, inclu
return binFile.Name(), nil, nil
}
-var fetchSrc = `
+var linuxSrc = `
[[INCLUDES]]
[[DEFAULTS]]
int printf(const char *format, ...);