aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-10-15 11:15:27 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-10-16 14:21:54 +0200
commitf78642861b4dbe396a67d5e2a750e22f83f3edd5 (patch)
treede2808e3e9d47aa1687b259e8ab48e34731532bc /pkg
parentd158fb9d3b6e03882c60a51854f149a8d2a637a0 (diff)
pkg/csource: support akaros
Diffstat (limited to 'pkg')
-rw-r--r--pkg/compiler/consts.go11
-rw-r--r--pkg/csource/akaros_common.go381
-rw-r--r--pkg/csource/csource.go276
-rw-r--r--pkg/csource/gen.go12
-rw-r--r--pkg/csource/linux_common.go (renamed from pkg/csource/common.go)2
5 files changed, 552 insertions, 130 deletions
diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go
index f4337cab1..61198c96a 100644
--- a/pkg/compiler/consts.go
+++ b/pkg/compiler/consts.go
@@ -42,8 +42,6 @@ func ExtractConsts(desc *ast.Description, target *targets.Target, eh0 ast.ErrorH
includeMap := make(map[string]bool)
incdirMap := make(map[string]bool)
constMap := make(map[string]bool)
- syscallNumbers := targets.OSList[target.OS].SyscallNumbers
- syscallPrefix := targets.OSList[target.OS].SyscallPrefix
ast.Walk(desc, func(n1 ast.Node) {
switch n := n1.(type) {
@@ -76,8 +74,8 @@ func ExtractConsts(desc *ast.Description, target *targets.Target, eh0 ast.ErrorH
info.Defines[name] = v
constMap[name] = true
case *ast.Call:
- if syscallNumbers && !strings.HasPrefix(n.CallName, "syz_") {
- constMap[syscallPrefix+n.CallName] = true
+ if target.SyscallNumbers && !strings.HasPrefix(n.CallName, "syz_") {
+ constMap[target.SyscallPrefix+n.CallName] = true
}
case *ast.Type:
if c := typeConstIdentifier(n); c != nil {
@@ -119,7 +117,6 @@ func (comp *compiler) assignSyscallNumbers(consts map[string]uint64) {
}
var top []ast.Node
- syscallPrefix := targets.OSList[comp.target.OS].SyscallPrefix
for _, decl := range comp.desc.Nodes {
switch decl.(type) {
case *ast.Call:
@@ -129,12 +126,12 @@ func (comp *compiler) assignSyscallNumbers(consts map[string]uint64) {
top = append(top, decl)
continue
}
- if !targets.OSList[comp.target.OS].SyscallNumbers {
+ if !comp.target.SyscallNumbers {
top = append(top, decl)
continue
}
// Lookup in consts.
- str := syscallPrefix + c.CallName
+ str := comp.target.SyscallPrefix + c.CallName
nr, ok := consts[str]
top = append(top, decl)
if ok {
diff --git a/pkg/csource/akaros_common.go b/pkg/csource/akaros_common.go
new file mode 100644
index 000000000..a02f0834c
--- /dev/null
+++ b/pkg/csource/akaros_common.go
@@ -0,0 +1,381 @@
+// AUTOGENERATED FROM executor/common_akaros.h
+package csource
+
+var commonHeaderAkaros = `
+
+
+#include <unistd.h>
+#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE)
+#include <pthread.h>
+#include <stdlib.h>
+#endif
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT))
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <time.h>
+#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV)
+#include <setjmp.h>
+#include <signal.h>
+#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
+#include <stdlib.h>
+#include <sys/stat.h>
+#endif
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR))
+#include <dirent.h>
+#endif
+
+#define doexit exit
+#define NORETURN __attribute__((noreturn))
+
+
+
+#include <stdint.h>
+#include <string.h>
+#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV)
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG)
+#include <stdarg.h>
+#include <stdio.h>
+#endif
+
+#if defined(SYZ_EXECUTOR)
+#ifndef SYSCALLAPI
+#define SYSCALLAPI
+#endif
+
+typedef long(SYSCALLAPI* syscall_t)(long, long, long, long, long, long, long, long, long);
+
+struct call_t {
+ const char* name;
+ int sys_nr;
+ syscall_t call;
+};
+
+extern call_t syscalls[];
+extern unsigned syscall_count;
+#endif
+
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
+ defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \
+ defined(SYZ_SANDBOX_SETUID) || defined(SYZ_FAULT_INJECTION) || defined(__NR_syz_kvm_setup_cpu)
+const int kFailStatus = 67;
+const int kRetryStatus = 69;
+#endif
+
+#if defined(SYZ_EXECUTOR)
+const int kErrorStatus = 68;
+#endif
+
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
+ defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \
+ defined(SYZ_SANDBOX_SETUID) || defined(SYZ_FAULT_INJECTION) || defined(__NR_syz_kvm_setup_cpu)
+NORETURN static void fail(const char* msg, ...)
+{
+ int e = errno;
+ fflush(stdout);
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, " (errno %d)\n", e);
+ doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
+}
+#endif
+
+#if defined(SYZ_EXECUTOR)
+NORETURN static void error(const char* msg, ...)
+{
+ fflush(stdout);
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ doexit(kErrorStatus);
+}
+#endif
+
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT))
+NORETURN static void exitf(const char* msg, ...)
+{
+ int e = errno;
+ fflush(stdout);
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fprintf(stderr, " (errno %d)\n", e);
+ doexit(kRetryStatus);
+}
+#endif
+
+#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG)
+static int flag_debug;
+
+static void debug(const char* msg, ...)
+{
+ if (!flag_debug)
+ return;
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fflush(stderr);
+}
+#endif
+
+#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_BITMASKS)
+#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1)
+
+#define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, (bf_len)) << (bf_off))
+
+#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \
+ if ((bf_off) == 0 && (bf_len) == 0) { \
+ *(type*)(addr) = (type)(val); \
+ } else { \
+ type new_val = *(type*)(addr); \
+ new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \
+ new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \
+ *(type*)(addr) = new_val; \
+ }
+#endif
+
+#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_CHECKSUMS)
+struct csum_inet {
+ uint32_t acc;
+};
+
+static void csum_inet_init(struct csum_inet* csum)
+{
+ csum->acc = 0;
+}
+
+static void csum_inet_update(struct csum_inet* csum, const uint8_t* data, size_t length)
+{
+ if (length == 0)
+ return;
+
+ size_t i;
+ for (i = 0; i < length - 1; i += 2)
+ csum->acc += *(uint16_t*)&data[i];
+
+ if (length & 1)
+ csum->acc += (uint16_t)data[length - 1];
+
+ while (csum->acc > 0xffff)
+ csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16);
+}
+
+static uint16_t csum_inet_digest(struct csum_inet* csum)
+{
+ return ~csum->acc;
+}
+#endif
+
+#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV)
+static __thread int skip_segv;
+static __thread jmp_buf segv_env;
+
+static void segv_handler(int sig, siginfo_t* info, void* ctx)
+{
+ uintptr_t addr = (uintptr_t)info->si_addr;
+ const uintptr_t prog_start = 1 << 20;
+ const uintptr_t prog_end = 100 << 20;
+ if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) {
+ debug("SIGSEGV on %p, skipping\n", addr);
+ siglongjmp(segv_env, 1);
+ }
+ debug("SIGSEGV on %p, exiting\n", addr);
+ doexit(sig);
+ for (;;) {
+ }
+}
+
+static void install_segv_handler()
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = segv_handler;
+ sa.sa_flags = SA_NODEFER | SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGSEGV, &sa, NULL);
+ sigaction(SIGBUS, &sa, NULL);
+}
+
+#define NONFAILING(...) \
+ { \
+ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ if (_setjmp(segv_env) == 0) { \
+ __VA_ARGS__; \
+ } \
+ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
+ }
+#endif
+
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT))
+static uint64_t current_time_ms()
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ fail("clock_gettime failed");
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+#endif
+
+#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
+static void use_temporary_dir()
+{
+ char tmpdir_template[] = "./syzkaller.XXXXXX";
+ char* tmpdir = mkdtemp(tmpdir_template);
+ if (!tmpdir)
+ fail("failed to mkdtemp");
+ if (chmod(tmpdir, 0777))
+ fail("failed to chmod");
+ if (chdir(tmpdir))
+ fail("failed to chdir");
+}
+#endif
+
+#if defined(SYZ_EXECUTOR)
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+#endif
+
+#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION)
+static int inject_fault(int nth)
+{
+ return 0;
+}
+
+static int fault_injected(int fail_fd)
+{
+ return 0;
+}
+#endif
+
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR))
+static void remove_dir(const char* dir)
+{
+ DIR* dp;
+ struct dirent* ep;
+ int iter = 0;
+retry:
+ dp = opendir(dir);
+ if (dp == NULL)
+ return;
+ while ((ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+ continue;
+ char filename[FILENAME_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
+ struct stat st;
+ if (lstat(filename, &st))
+ return;
+ if (S_ISDIR(st.st_mode)) {
+ remove_dir(filename);
+ continue;
+ }
+ int i;
+ for (i = 0;; i++) {
+ if (unlink(filename) == 0)
+ break;
+ if (errno == EROFS)
+ break;
+ if (errno != EBUSY || i > 100)
+ return;
+ }
+ }
+ closedir(dp);
+ int i;
+ for (i = 0;; i++) {
+ if (rmdir(dir) == 0)
+ break;
+ if (i < 100) {
+ if (errno == EROFS)
+ break;
+ if (errno == ENOTEMPTY) {
+ if (iter < 100) {
+ iter++;
+ goto retry;
+ }
+ }
+ }
+ return;
+ }
+}
+#endif
+
+#if defined(SYZ_REPEAT)
+static void test();
+
+#if defined(SYZ_WAIT_REPEAT)
+void loop()
+{
+ int iter;
+ for (iter = 0;; iter++) {
+#ifdef SYZ_USE_TMP_DIR
+ char cwdbuf[256];
+ sprintf(cwdbuf, "./%d", iter);
+ if (mkdir(cwdbuf, 0777))
+ fail("failed to mkdir");
+#endif
+ int pid = fork();
+ if (pid < 0)
+ fail("clone failed");
+ if (pid == 0) {
+#ifdef SYZ_USE_TMP_DIR
+ if (chdir(cwdbuf))
+ fail("failed to chdir");
+#endif
+ test();
+ doexit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ int res = waitpid(-1, &status, WNOHANG);
+ if (res == pid)
+ break;
+ usleep(1000);
+ if (current_time_ms() - start > 5 * 1000) {
+ kill(pid, SIGKILL);
+ while (waitpid(-1, &status, 0) != pid) {
+ }
+ break;
+ }
+ }
+#ifdef SYZ_USE_TMP_DIR
+ remove_dir(cwdbuf);
+#endif
+ }
+}
+#else
+void loop()
+{
+ while (1) {
+ test();
+ }
+}
+#endif
+#endif
+`
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index b0d44a94f..1bc1ec5ba 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -1,17 +1,13 @@
// 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.
-// I heard you like shell...
-//go:generate bash -c "echo -e '// AUTOGENERATED FROM executor/common_linux.h\npackage csource\nvar commonHeader = `' > common.go; cat ../../executor/common_linux.h | sed -e '/#include \"common.h\"/ {' -e 'r ../../executor/common.h' -e 'd' -e '}' - | sed -e '/#include \"common_kvm_amd64.h\"/ {' -e 'r ../../executor/common_kvm_amd64.h' -e 'd' -e '}' - | sed -e '/#include \"common_kvm_arm64.h\"/ {' -e 'r ../../executor/common_kvm_arm64.h' -e 'd' -e '}' - | sed -e '/#include \"kvm.h\"/ {' -e 'r ../../executor/kvm.h' -e 'd' -e '}' - | sed -e '/#include \"kvm.S.h\"/ {' -e 'r ../../executor/kvm.S.h' -e 'd' -e '}' - | egrep -v '^[ ]*//' | sed '/^[ ]*\\/\\/.*/d' | sed 's#[ ]*//.*##g' >> common.go; echo '`' >> common.go"
-//go:generate go fmt common.go
-
+// Package csource generates [almost] equivalent C programs from syzkaller programs.
package csource
import (
"bytes"
"errors"
"fmt"
- "io"
"io/ioutil"
"os"
"os/exec"
@@ -71,122 +67,119 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
if err := opts.Check(); err != nil {
return nil, fmt.Errorf("csource: invalid opts: %v", err)
}
- exec := make([]byte, prog.ExecBufferSize)
- if _, err := p.SerializeForExec(exec, 0); err != nil {
- return nil, fmt.Errorf("failed to serialize program: %v", err)
+ commonHeader := ""
+ switch p.Target.OS {
+ case "linux":
+ commonHeader = commonHeaderLinux
+ case "akaros":
+ commonHeader = commonHeaderAkaros
+ default:
+ return nil, fmt.Errorf("unsupported OS: %v", p.Target.OS)
+ }
+ ctx := &context{
+ p: p,
+ opts: opts,
+ target: p.Target,
+ sysTarget: targets.List[p.Target.OS][p.Target.Arch],
+ w: new(bytes.Buffer),
+ calls: make(map[string]uint64),
}
- w := new(bytes.Buffer)
-
- fmt.Fprint(w, "// autogenerated by syzkaller (http://github.com/google/syzkaller)\n\n")
-
- handled := make(map[string]uint64)
for _, c := range p.Calls {
- handled[c.Meta.CallName] = c.Meta.NR
+ ctx.calls[c.Meta.CallName] = c.Meta.NR
}
- hdr, err := preprocessCommonHeader(p.Target, opts, handled, prog.RequiresBitmasks(p), prog.RequiresChecksums(p))
+
+ ctx.print("// autogenerated by syzkaller (http://github.com/google/syzkaller)\n\n")
+
+ hdr, err := ctx.preprocessCommonHeader(commonHeader)
if err != nil {
return nil, err
}
- fmt.Fprint(w, hdr)
- fmt.Fprint(w, "\n")
+ ctx.print(hdr)
+ ctx.print("\n")
- for name, nr := range handled {
- if strings.HasPrefix(name, "syz_") {
- continue
- }
- if p.Target.OS == "linux" && p.Target.Arch == "amd64" && nr < 313 {
- // Only generate defines for new syscalls (added after commit 8a1ab3155c2ac on 2012-10-04).
- continue
- }
- fmt.Fprintf(w, "#ifndef __NR_%v\n", name)
- fmt.Fprintf(w, "#define __NR_%v %v\n", name, nr)
- fmt.Fprintf(w, "#endif\n")
- }
- if p.Target.OS == "linux" && p.Target.PtrSize == 4 {
- // This is a dirty hack.
- // On 32-bit linux mmap translated to old_mmap syscall which has a different signature.
- // mmap2 has the right signature. executor translates mmap to mmap2, do the same here.
- fmt.Fprintf(w, "#undef __NR_mmap\n")
- fmt.Fprintf(w, "#define __NR_mmap __NR_mmap2\n")
- }
- fmt.Fprintf(w, "\n")
+ ctx.generateSyscallDefines()
- calls, nvar := generateCalls(p.Target, exec, opts)
- fmt.Fprintf(w, "long r[%v];\n", nvar)
+ exec := make([]byte, prog.ExecBufferSize)
+ progSize, err := ctx.p.SerializeForExec(exec, 0)
+ if err != nil {
+ return nil, fmt.Errorf("failed to serialize program: %v", err)
+ }
+ calls, nvar := ctx.generateCalls(exec[:progSize])
+ ctx.printf("long r[%v];\n", nvar)
if !opts.Repeat {
- generateTestFunc(w, opts, calls, "loop")
+ ctx.generateTestFunc(calls, "loop")
- fmt.Fprint(w, "int main()\n{\n")
+ ctx.print("int main()\n{\n")
if opts.HandleSegv {
- fmt.Fprintf(w, "\tinstall_segv_handler();\n")
+ ctx.printf("\tinstall_segv_handler();\n")
}
if opts.UseTmpDir {
- fmt.Fprintf(w, "\tuse_temporary_dir();\n")
+ ctx.printf("\tuse_temporary_dir();\n")
}
if opts.Sandbox != "" {
- fmt.Fprintf(w, "\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun)
- fmt.Fprint(w, "\tint status = 0;\n")
- fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
+ ctx.printf("\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun)
+ ctx.print("\tint status = 0;\n")
+ ctx.print("\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
} else {
if opts.EnableTun {
- fmt.Fprintf(w, "\tsetup_tun(0, %v);\n", opts.EnableTun)
+ ctx.printf("\tsetup_tun(0, %v);\n", opts.EnableTun)
}
- fmt.Fprint(w, "\tloop();\n")
+ ctx.print("\tloop();\n")
}
- fmt.Fprint(w, "\treturn 0;\n}\n")
+ ctx.print("\treturn 0;\n}\n")
} else {
- generateTestFunc(w, opts, calls, "test")
+ ctx.generateTestFunc(calls, "test")
if opts.Procs <= 1 {
- fmt.Fprint(w, "int main()\n{\n")
+ ctx.print("int main()\n{\n")
if opts.HandleSegv {
- fmt.Fprintf(w, "\tinstall_segv_handler();\n")
+ ctx.printf("\tinstall_segv_handler();\n")
}
if opts.UseTmpDir {
- fmt.Fprintf(w, "\tuse_temporary_dir();\n")
+ ctx.printf("\tuse_temporary_dir();\n")
}
if opts.Sandbox != "" {
- fmt.Fprintf(w, "\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun)
- fmt.Fprint(w, "\tint status = 0;\n")
- fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
+ ctx.printf("\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun)
+ ctx.print("\tint status = 0;\n")
+ ctx.print("\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
} else {
if opts.EnableTun {
- fmt.Fprintf(w, "\tsetup_tun(0, %v);\n", opts.EnableTun)
+ ctx.printf("\tsetup_tun(0, %v);\n", opts.EnableTun)
}
- fmt.Fprint(w, "\tloop();\n")
+ ctx.print("\tloop();\n")
}
- fmt.Fprint(w, "\treturn 0;\n}\n")
+ ctx.print("\treturn 0;\n}\n")
} else {
- fmt.Fprint(w, "int main()\n{\n")
- fmt.Fprint(w, "\tint i;")
- fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", opts.Procs)
- fmt.Fprint(w, "\t\tif (fork() == 0) {\n")
+ ctx.print("int main()\n{\n")
+ ctx.print("\tint i;")
+ ctx.printf("\tfor (i = 0; i < %v; i++) {\n", opts.Procs)
+ ctx.print("\t\tif (fork() == 0) {\n")
if opts.HandleSegv {
- fmt.Fprintf(w, "\t\t\tinstall_segv_handler();\n")
+ ctx.printf("\t\t\tinstall_segv_handler();\n")
}
if opts.UseTmpDir {
- fmt.Fprintf(w, "\t\t\tuse_temporary_dir();\n")
+ ctx.printf("\t\t\tuse_temporary_dir();\n")
}
if opts.Sandbox != "" {
- fmt.Fprintf(w, "\t\t\tint pid = do_sandbox_%v(i, %v);\n", opts.Sandbox, opts.EnableTun)
- fmt.Fprint(w, "\t\t\tint status = 0;\n")
- fmt.Fprint(w, "\t\t\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
+ ctx.printf("\t\t\tint pid = do_sandbox_%v(i, %v);\n", opts.Sandbox, opts.EnableTun)
+ ctx.print("\t\t\tint status = 0;\n")
+ ctx.print("\t\t\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
} else {
if opts.EnableTun {
- fmt.Fprintf(w, "\t\t\tsetup_tun(i, %v);\n", opts.EnableTun)
+ ctx.printf("\t\t\tsetup_tun(i, %v);\n", opts.EnableTun)
}
- fmt.Fprint(w, "\t\t\tloop();\n")
+ ctx.print("\t\t\tloop();\n")
}
- fmt.Fprint(w, "\t\t\treturn 0;\n")
- fmt.Fprint(w, "\t\t}\n")
- fmt.Fprint(w, "\t}\n")
- fmt.Fprint(w, "\tsleep(1000000);\n")
- fmt.Fprint(w, "\treturn 0;\n}\n")
+ ctx.print("\t\t\treturn 0;\n")
+ ctx.print("\t\t}\n")
+ ctx.print("\t}\n")
+ ctx.print("\tsleep(1000000);\n")
+ ctx.print("\treturn 0;\n}\n")
}
}
// Remove NONFAILING and debug calls.
- out0 := w.String()
+ out0 := ctx.w.String()
if !opts.HandleSegv {
re := regexp.MustCompile(`\t*NONFAILING\((.*)\);\n`)
out0 = re.ReplaceAllString(out0, "$1;\n")
@@ -211,64 +204,102 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
return out1, nil
}
-func generateTestFunc(w io.Writer, opts Options, calls []string, name string) {
+type context struct {
+ p *prog.Prog
+ opts Options
+ target *prog.Target
+ sysTarget *targets.Target
+ w *bytes.Buffer
+ calls map[string]uint64 // CallName -> NR
+}
+
+func (ctx *context) print(str string) {
+ ctx.w.WriteString(str)
+}
+
+func (ctx *context) printf(str string, args ...interface{}) {
+ ctx.print(fmt.Sprintf(str, args...))
+}
+
+func (ctx *context) generateTestFunc(calls []string, name string) {
+ opts := ctx.opts
if !opts.Threaded && !opts.Collide {
- fmt.Fprintf(w, "void %v()\n{\n", name)
+ ctx.printf("void %v()\n{\n", name)
if opts.Debug {
// Use debug to avoid: error: ‘debug’ defined but not used.
- fmt.Fprintf(w, "\tdebug(\"%v\\n\");\n", name)
+ ctx.printf("\tdebug(\"%v\\n\");\n", name)
}
if opts.Repro {
- fmt.Fprintf(w, "\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
+ ctx.printf("\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
}
- fmt.Fprintf(w, "\tmemset(r, -1, sizeof(r));\n")
+ ctx.printf("\tmemset(r, -1, sizeof(r));\n")
for _, c := range calls {
- fmt.Fprintf(w, "%s", c)
+ ctx.printf("%s", c)
}
- fmt.Fprintf(w, "}\n\n")
+ ctx.printf("}\n\n")
} else {
- fmt.Fprintf(w, "void *thr(void *arg)\n{\n")
- fmt.Fprintf(w, "\tswitch ((long)arg) {\n")
+ ctx.printf("void *thr(void *arg)\n{\n")
+ ctx.printf("\tswitch ((long)arg) {\n")
for i, c := range calls {
- fmt.Fprintf(w, "\tcase %v:\n", i)
- fmt.Fprintf(w, "%s", strings.Replace(c, "\t", "\t\t", -1))
- fmt.Fprintf(w, "\t\tbreak;\n")
+ ctx.printf("\tcase %v:\n", i)
+ ctx.printf("%s", strings.Replace(c, "\t", "\t\t", -1))
+ ctx.printf("\t\tbreak;\n")
}
- fmt.Fprintf(w, "\t}\n")
- fmt.Fprintf(w, "\treturn 0;\n}\n\n")
+ ctx.printf("\t}\n")
+ ctx.printf("\treturn 0;\n}\n\n")
- fmt.Fprintf(w, "void %v()\n{\n", name)
- fmt.Fprintf(w, "\tlong i;\n")
- fmt.Fprintf(w, "\tpthread_t th[%v];\n", 2*len(calls))
- fmt.Fprintf(w, "\n")
+ ctx.printf("void %v()\n{\n", name)
+ ctx.printf("\tlong i;\n")
+ ctx.printf("\tpthread_t th[%v];\n", 2*len(calls))
+ ctx.printf("\n")
if opts.Debug {
// Use debug to avoid: error: ‘debug’ defined but not used.
- fmt.Fprintf(w, "\tdebug(\"%v\\n\");\n", name)
+ ctx.printf("\tdebug(\"%v\\n\");\n", name)
}
if opts.Repro {
- fmt.Fprintf(w, "\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
+ ctx.printf("\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
}
- fmt.Fprintf(w, "\tmemset(r, -1, sizeof(r));\n")
+ ctx.printf("\tmemset(r, -1, sizeof(r));\n")
if opts.Collide {
- fmt.Fprintf(w, "\tsrand(getpid());\n")
+ ctx.printf("\tsrand(getpid());\n")
}
- fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", len(calls))
- fmt.Fprintf(w, "\t\tpthread_create(&th[i], 0, thr, (void*)i);\n")
- fmt.Fprintf(w, "\t\tusleep(rand()%%10000);\n")
- fmt.Fprintf(w, "\t}\n")
+ ctx.printf("\tfor (i = 0; i < %v; i++) {\n", len(calls))
+ ctx.printf("\t\tpthread_create(&th[i], 0, thr, (void*)i);\n")
+ ctx.printf("\t\tusleep(rand()%%10000);\n")
+ ctx.printf("\t}\n")
if opts.Collide {
- fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", len(calls))
- fmt.Fprintf(w, "\t\tpthread_create(&th[%v+i], 0, thr, (void*)i);\n", len(calls))
- fmt.Fprintf(w, "\t\tif (rand()%%2)\n")
- fmt.Fprintf(w, "\t\t\tusleep(rand()%%10000);\n")
- fmt.Fprintf(w, "\t}\n")
+ ctx.printf("\tfor (i = 0; i < %v; i++) {\n", len(calls))
+ ctx.printf("\t\tpthread_create(&th[%v+i], 0, thr, (void*)i);\n", len(calls))
+ ctx.printf("\t\tif (rand()%%2)\n")
+ ctx.printf("\t\t\tusleep(rand()%%10000);\n")
+ ctx.printf("\t}\n")
+ }
+ ctx.printf("\tusleep(rand()%%100000);\n")
+ ctx.printf("}\n\n")
+ }
+}
+
+func (ctx *context) generateSyscallDefines() {
+ prefix := ctx.sysTarget.SyscallPrefix
+ for name, nr := range ctx.calls {
+ if strings.HasPrefix(name, "syz_") || !ctx.sysTarget.NeedSyscallDefine(nr) {
+ continue
}
- fmt.Fprintf(w, "\tusleep(rand()%%100000);\n")
- fmt.Fprintf(w, "}\n\n")
+ ctx.printf("#ifndef %v%v\n", prefix, name)
+ ctx.printf("#define %v%v %v\n", prefix, name, nr)
+ ctx.printf("#endif\n")
+ }
+ if ctx.target.OS == "linux" && ctx.target.PtrSize == 4 {
+ // This is a dirty hack.
+ // On 32-bit linux mmap translated to old_mmap syscall which has a different signature.
+ // mmap2 has the right signature. executor translates mmap to mmap2, do the same here.
+ ctx.printf("#undef __NR_mmap\n")
+ ctx.printf("#define __NR_mmap __NR_mmap2\n")
}
+ ctx.printf("\n")
}
-func generateCalls(target *prog.Target, exec []byte, opts Options) ([]string, int) {
+func (ctx *context) generateCalls(exec []byte) ([]string, int) {
read := func() uint64 {
if len(exec) < 8 {
panic("exec program overflow")
@@ -372,23 +403,25 @@ loop:
default:
// Normal syscall.
newCall()
- if opts.Fault && opts.FaultCall == len(calls) {
+ if ctx.opts.Fault && ctx.opts.FaultCall == len(calls) {
fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/failslab/ignore-gfp-wait\", \"N\");\n")
fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_futex/ignore-private\", \"N\");\n")
- fmt.Fprintf(w, "\tinject_fault(%v);\n", opts.FaultNth)
+ fmt.Fprintf(w, "\tinject_fault(%v);\n", ctx.opts.FaultNth)
}
- meta := target.Syscalls[instr]
+ meta := ctx.target.Syscalls[instr]
emitCall := true
if meta.CallName == "syz_test" {
emitCall = false
}
- if !opts.EnableTun && (meta.CallName == "syz_emit_ethernet" || meta.CallName == "syz_extract_tcp_res") {
+ if !ctx.opts.EnableTun && (meta.CallName == "syz_emit_ethernet" ||
+ meta.CallName == "syz_extract_tcp_res") {
emitCall = false
}
native := !strings.HasPrefix(meta.CallName, "syz_")
if emitCall {
if native {
- fmt.Fprintf(w, "\tr[%v] = syscall(__NR_%v", n, meta.CallName)
+ fmt.Fprintf(w, "\tr[%v] = syscall(%v%v",
+ n, ctx.sysTarget.SyscallPrefix, meta.CallName)
} else {
fmt.Fprintf(w, "\tr[%v] = %v(", n, meta.CallName)
}
@@ -430,14 +463,15 @@ loop:
return calls, n
}
-func preprocessCommonHeader(target *prog.Target, opts Options, handled map[string]uint64, useBitmasks, useChecksums bool) (string, error) {
+func (ctx *context) preprocessCommonHeader(commonHeader string) (string, error) {
var defines []string
- if useBitmasks {
+ if prog.RequiresBitmasks(ctx.p) {
defines = append(defines, "SYZ_USE_BITMASKS")
}
- if useChecksums {
+ if prog.RequiresChecksums(ctx.p) {
defines = append(defines, "SYZ_USE_CHECKSUMS")
}
+ opts := ctx.opts
switch opts.Sandbox {
case "":
// No sandbox, do nothing.
@@ -477,12 +511,10 @@ func preprocessCommonHeader(target *prog.Target, opts Options, handled map[strin
if opts.Debug {
defines = append(defines, "SYZ_DEBUG")
}
- for name, _ := range handled {
+ for name, _ := range ctx.calls {
defines = append(defines, "__NR_"+name)
}
-
- sysTarget := targets.List[target.OS][target.Arch]
- defines = append(defines, sysTarget.CArch...)
+ defines = append(defines, ctx.sysTarget.CArch...)
cmd := exec.Command("cpp", "-nostdinc", "-undef", "-fdirectives-only", "-dDI", "-E", "-P", "-")
for _, def := range defines {
diff --git a/pkg/csource/gen.go b/pkg/csource/gen.go
new file mode 100644
index 000000000..103a6215e
--- /dev/null
+++ b/pkg/csource/gen.go
@@ -0,0 +1,12 @@
+// 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.
+
+// I heard you like shell...
+
+//go:generate bash -c "echo -e '// AUTOGENERATED FROM executor/common_linux.h\npackage csource\nvar commonHeaderLinux = `' > linux_common.go; cat ../../executor/common_linux.h | sed -e '/#include \"common.h\"/ {' -e 'r ../../executor/common.h' -e 'd' -e '}' - | sed -e '/#include \"common_kvm_amd64.h\"/ {' -e 'r ../../executor/common_kvm_amd64.h' -e 'd' -e '}' - | sed -e '/#include \"common_kvm_arm64.h\"/ {' -e 'r ../../executor/common_kvm_arm64.h' -e 'd' -e '}' - | sed -e '/#include \"kvm.h\"/ {' -e 'r ../../executor/kvm.h' -e 'd' -e '}' - | sed -e '/#include \"kvm.S.h\"/ {' -e 'r ../../executor/kvm.S.h' -e 'd' -e '}' - | egrep -v '^[ ]*//' | sed '/^[ ]*\\/\\/.*/d' | sed 's#[ ]*//.*##g' >> linux_common.go; echo '`' >> linux_common.go"
+//go:generate go fmt linux_common.go
+
+//go:generate bash -c "echo -e '// AUTOGENERATED FROM executor/common_akaros.h\npackage csource\nvar commonHeaderAkaros = `' > akaros_common.go; cat ../../executor/common_akaros.h | sed -e '/#include \"common.h\"/ {' -e 'r ../../executor/common.h' -e 'd' -e '}' - | egrep -v '^[ ]*//' | sed '/^[ ]*\\/\\/.*/d' | sed 's#[ ]*//.*##g' >> akaros_common.go; echo '`' >> akaros_common.go"
+//go:generate go fmt akaros_common.go
+
+package csource
diff --git a/pkg/csource/common.go b/pkg/csource/linux_common.go
index f11b5360c..b86424ff9 100644
--- a/pkg/csource/common.go
+++ b/pkg/csource/linux_common.go
@@ -1,7 +1,7 @@
// AUTOGENERATED FROM executor/common_linux.h
package csource
-var commonHeader = `
+var commonHeaderLinux = `
#ifndef _GNU_SOURCE