diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-09-25 08:47:15 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-09-25 08:47:48 +0200 |
| commit | e9c477a5b3a05a614d9a0c68ba9724762a363784 (patch) | |
| tree | a89fbfd6c3f8543f0b86a4c8c68c365a53a40ba1 | |
| parent | 8f8cf20bd23a37aaf4ac3a7ec3fab2370ef2a755 (diff) | |
sys/syz-extract: support fuchsia
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | docs/syscall_descriptions.md | 23 | ||||
| -rw-r--r-- | executor/syscalls_fuchsia.h | 4 | ||||
| -rw-r--r-- | pkg/compiler/compiler_test.go | 5 | ||||
| -rw-r--r-- | pkg/compiler/consts.go | 5 | ||||
| -rw-r--r-- | pkg/compiler/consts_test.go | 7 | ||||
| -rw-r--r-- | sys/fuchsia/amd64.go | 8 | ||||
| -rw-r--r-- | sys/fuchsia/arm64.go | 28 | ||||
| -rw-r--r-- | sys/fuchsia/sys.txt | 4 | ||||
| -rw-r--r-- | sys/fuchsia/sys_amd64.const | 28 | ||||
| -rw-r--r-- | sys/fuchsia/sys_arm64.const | 23 | ||||
| -rwxr-xr-x | sys/linux/extract.sh | 46 | ||||
| -rw-r--r-- | sys/syz-extract/extract.go | 139 | ||||
| -rw-r--r-- | sys/syz-extract/fuchsia.go | 107 | ||||
| -rw-r--r-- | sys/syz-extract/linux.go (renamed from sys/syz-extract/fetch.go) | 81 |
15 files changed, 333 insertions, 181 deletions
@@ -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, ...); |
