From 7d7c9c550f5d83c652719be31a350a9f8f306b3c Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 17 May 2017 20:20:23 +0200 Subject: csource: add EnableTun option --- csource/csource_test.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'csource/csource_test.go') diff --git a/csource/csource_test.go b/csource/csource_test.go index abff96f72..8ca7bb5ce 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -32,20 +32,22 @@ func allOptionsPermutations() []Options { for _, opt.Threaded = range []bool{false, true} { for _, opt.Collide = range []bool{false, true} { for _, opt.Repeat = range []bool{false, true} { - for _, opt.Repro = range []bool{false, true} { - for _, opt.Procs = range []int{1, 4} { - for _, opt.Sandbox = range []string{"none", "setuid", "namespace"} { - for _, opt.Fault = range []bool{false, true} { - if opt.Collide && !opt.Threaded { - continue + for _, opt.Procs = range []int{1, 4} { + for _, opt.Sandbox = range []string{"none", "setuid", "namespace"} { + for _, opt.Repro = range []bool{false, true} { + for _, opt.EnableTun = range []bool{false, true} { + for _, opt.Fault = range []bool{false, true} { + if opt.Collide && !opt.Threaded { + continue + } + if !opt.Repeat && opt.Procs != 1 { + continue + } + if testing.Short() && opt.Procs != 1 { + continue + } + options = append(options, opt) } - if !opt.Repeat && opt.Procs != 1 { - continue - } - if testing.Short() && opt.Procs != 1 { - continue - } - options = append(options, opt) } } } -- cgit mrf-deployment From 5597911fbf26237b9d11a0f6293e4b52b2d9069c Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 18 May 2017 14:26:02 +0200 Subject: csource: use tmp dir only when necessary --- csource/common.go | 5 ++++- csource/csource.go | 16 +++++++++++++--- csource/csource_test.go | 24 +++++++++++++----------- executor/common.h | 2 ++ repro/repro.go | 12 ++++++++++++ tools/syz-prog2c/prog2c.go | 2 ++ 6 files changed, 46 insertions(+), 15 deletions(-) (limited to 'csource/csource_test.go') diff --git a/csource/common.go b/csource/common.go index 048df6f52..8fa531598 100644 --- a/csource/common.go +++ b/csource/common.go @@ -150,7 +150,9 @@ static void install_segv_handler() sigaction(SIGBUS, &sa, NULL); } -static void use_temporary_dir() { +#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) @@ -160,6 +162,7 @@ static void use_temporary_dir() { if (chdir(tmpdir)) fail("failed to chdir"); } +#endif #define NONFAILING(...) \ { \ diff --git a/csource/csource.go b/csource/csource.go index b41c5ca11..bc50bf2ea 100644 --- a/csource/csource.go +++ b/csource/csource.go @@ -34,6 +34,7 @@ type Options struct { // These options allow for a more fine-tuned control over the generated C code. EnableTun bool + UseTmpDir bool // Generate code for use with repro package to prints log messages, // which allows to distinguish between a hang and an absent crash. @@ -75,7 +76,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { fmt.Fprint(w, "int main()\n{\n") fmt.Fprintf(w, "\tinstall_segv_handler();\n") - fmt.Fprintf(w, "\tuse_temporary_dir();\n") + if opts.UseTmpDir { + fmt.Fprintf(w, "\tuse_temporary_dir();\n") + } 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") @@ -85,7 +88,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { if opts.Procs <= 1 { fmt.Fprint(w, "int main()\n{\n") fmt.Fprintf(w, "\tinstall_segv_handler();\n") - fmt.Fprintf(w, "\tuse_temporary_dir();\n") + if opts.UseTmpDir { + fmt.Fprintf(w, "\tuse_temporary_dir();\n") + } 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") @@ -96,7 +101,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", opts.Procs) fmt.Fprint(w, "\t\tif (fork() == 0) {\n") fmt.Fprintf(w, "\t\t\tinstall_segv_handler();\n") - fmt.Fprintf(w, "\t\t\tuse_temporary_dir();\n") + if opts.UseTmpDir { + fmt.Fprintf(w, "\t\t\tuse_temporary_dir();\n") + } 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") @@ -327,6 +334,9 @@ func preprocessCommonHeader(opts Options, handled map[string]int) (string, error if opts.EnableTun { defines = append(defines, "SYZ_TUN_ENABLE") } + if opts.UseTmpDir { + defines = append(defines, "SYZ_USE_TMP_DIR") + } for name, _ := range handled { defines = append(defines, "__NR_"+name) } diff --git a/csource/csource_test.go b/csource/csource_test.go index 8ca7bb5ce..3e09a3019 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -35,18 +35,20 @@ func allOptionsPermutations() []Options { for _, opt.Procs = range []int{1, 4} { for _, opt.Sandbox = range []string{"none", "setuid", "namespace"} { for _, opt.Repro = range []bool{false, true} { - for _, opt.EnableTun = range []bool{false, true} { - for _, opt.Fault = range []bool{false, true} { - if opt.Collide && !opt.Threaded { - continue + for _, opt.Fault = range []bool{false, true} { + for _, opt.EnableTun = range []bool{false, true} { + for _, opt.UseTmpDir = range []bool{false, true} { + if opt.Collide && !opt.Threaded { + continue + } + if !opt.Repeat && opt.Procs != 1 { + continue + } + if testing.Short() && opt.Procs != 1 { + continue + } + options = append(options, opt) } - if !opt.Repeat && opt.Procs != 1 { - continue - } - if testing.Short() && opt.Procs != 1 { - continue - } - options = append(options, opt) } } } diff --git a/executor/common.h b/executor/common.h index 92467dc26..99c3fb9f3 100644 --- a/executor/common.h +++ b/executor/common.h @@ -175,6 +175,7 @@ static void install_segv_handler() sigaction(SIGBUS, &sa, NULL); } +#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) static void use_temporary_dir() { char tmpdir_template[] = "./syzkaller.XXXXXX"; @@ -186,6 +187,7 @@ static void use_temporary_dir() if (chdir(tmpdir)) fail("failed to chdir"); } +#endif #define NONFAILING(...) \ { \ diff --git a/repro/repro.go b/repro/repro.go index 2f713c89f..3ae553bac 100644 --- a/repro/repro.go +++ b/repro/repro.go @@ -157,6 +157,7 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er Procs: ctx.cfg.Procs, Sandbox: ctx.cfg.Sandbox, EnableTun: true, + UseTmpDir: true, Repro: true, } // Execute the suspected programs. @@ -287,6 +288,17 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er res.Opts = opts } } + if res.Opts.UseTmpDir { + opts = res.Opts + opts.UseTmpDir = false + crashed, err := ctx.testCProg(res.Prog, duration, opts) + if err != nil { + return res, err + } + if crashed { + res.Opts = opts + } + } return res, nil } diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go index d0d81be3b..878772d42 100644 --- a/tools/syz-prog2c/prog2c.go +++ b/tools/syz-prog2c/prog2c.go @@ -23,6 +23,7 @@ var ( flagFaultCall = flag.Int("fault_call", -1, "inject fault into this call (0-based)") flagFaultNth = flag.Int("fault_nth", 0, "inject fault on n-th operation (0-based)") flagEnableTun = flag.Bool("tun", false, "set up TUN/TAP interface") + flagUseTmpDir = flag.Bool("tmpdir", false, "create a temporary dir and execute inside it") ) func main() { @@ -51,6 +52,7 @@ func main() { FaultCall: *flagFaultCall, FaultNth: *flagFaultNth, EnableTun: *flagEnableTun, + UseTmpDir: *flagUseTmpDir, Repro: false, } src, err := csource.Write(p, opts) -- cgit mrf-deployment From 10c9064bfc4890e5895057021280a0558131e3eb Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 18 May 2017 14:54:02 +0200 Subject: csource: only handle SIGSEGV when necessary --- csource/common.go | 33 ++++++++++++++++++++++++--------- csource/csource.go | 40 +++++++++++++++++++++++++++------------- csource/csource_test.go | 20 +++++++++++--------- executor/common.h | 29 ++++++++++++++++++++--------- executor/common_kvm_amd64.h | 9 +++++++++ repro/repro.go | 28 ++++++++++++++++++++-------- tools/syz-prog2c/prog2c.go | 44 +++++++++++++++++++++++--------------------- 7 files changed, 134 insertions(+), 69 deletions(-) (limited to 'csource/csource_test.go') diff --git a/csource/common.go b/csource/common.go index b748a555a..8d4a74146 100644 --- a/csource/common.go +++ b/csource/common.go @@ -116,6 +116,7 @@ void debug(const char* msg, ...) fflush(stdout); } +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) __thread int skip_segv; __thread jmp_buf segv_env; @@ -150,6 +151,16 @@ static void install_segv_handler() 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_USE_TMP_DIR) static void use_temporary_dir() { @@ -164,15 +175,6 @@ static void use_temporary_dir() } #endif -#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); \ - } - #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)) @@ -433,8 +435,13 @@ static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2) } struct tcp_resources* res = (struct tcp_resources*)a0; +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) NONFAILING(res->seq = htonl((ntohl(tcphdr->seq) + (uint32_t)a1))); NONFAILING(res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32_t)a2))); +#else + res->seq = htonl((ntohl(tcphdr->seq) + (uint32_t)a1)); + res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32_t)a2)); +#endif debug("extracted seq: %08x\n", res->seq); debug("extracted ack: %08x\n", res->ack); @@ -453,7 +460,11 @@ static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2) } else { char buf[1024]; char* hash; +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) NONFAILING(strncpy(buf, (char*)a0, sizeof(buf))); +#else + strncpy(buf, (char*)a0, sizeof(buf)); +#endif buf[sizeof(buf) - 1] = 0; while ((hash = strchr(buf, '#'))) { *hash = '0' + (char)(a1 % 10); @@ -539,6 +550,10 @@ static uintptr_t syz_fuseblk_mount(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin +#ifndef NONFAILING +#define NONFAILING(x) { x; } +#endif + const char kvm_asm16_cpl3[] = "\x0f\x20\xc0\x66\x83\xc8\x01\x0f\x22\xc0\xb8\xa0\x00\x0f\x00\xd8\xb8\x2b\x00\x8e\xd8\x8e\xc0\x8e\xe0\x8e\xe8\xbc\x00\x01\xc7\x06\x00\x01\x1d\xba\xc7\x06\x02\x01\x23\x00\xc7\x06\x04\x01\x00\x01\xc7\x06\x06\x01\x2b\x00\xcb"; const char kvm_asm32_paged[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0"; const char kvm_asm32_vm86[] = "\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0\x00"; diff --git a/csource/csource.go b/csource/csource.go index bc50bf2ea..ccc235f7e 100644 --- a/csource/csource.go +++ b/csource/csource.go @@ -33,8 +33,9 @@ type Options struct { FaultNth int // These options allow for a more fine-tuned control over the generated C code. - EnableTun bool - UseTmpDir bool + EnableTun bool + UseTmpDir bool + HandleSegv bool // Generate code for use with repro package to prints log messages, // which allows to distinguish between a hang and an absent crash. @@ -75,7 +76,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { generateTestFunc(w, opts, calls, "loop") fmt.Fprint(w, "int main()\n{\n") - fmt.Fprintf(w, "\tinstall_segv_handler();\n") + if opts.HandleSegv { + fmt.Fprintf(w, "\tinstall_segv_handler();\n") + } if opts.UseTmpDir { fmt.Fprintf(w, "\tuse_temporary_dir();\n") } @@ -87,7 +90,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { generateTestFunc(w, opts, calls, "test") if opts.Procs <= 1 { fmt.Fprint(w, "int main()\n{\n") - fmt.Fprintf(w, "\tinstall_segv_handler();\n") + if opts.HandleSegv { + fmt.Fprintf(w, "\tinstall_segv_handler();\n") + } if opts.UseTmpDir { fmt.Fprintf(w, "\tuse_temporary_dir();\n") } @@ -100,7 +105,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { 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") - fmt.Fprintf(w, "\t\t\tinstall_segv_handler();\n") + if opts.HandleSegv { + fmt.Fprintf(w, "\t\t\tinstall_segv_handler();\n") + } if opts.UseTmpDir { fmt.Fprintf(w, "\t\t\tuse_temporary_dir();\n") } @@ -136,7 +143,7 @@ func generateTestFunc(w io.Writer, opts Options, calls []string, name string) { for _, c := range calls { fmt.Fprintf(w, "%s", c) } - fmt.Fprintf(w, "}\n") + fmt.Fprintf(w, "}\n\n") } else { fmt.Fprintf(w, "void *thr(void *arg)\n{\n") fmt.Fprintf(w, "\tswitch ((long)arg) {\n") @@ -193,6 +200,10 @@ func generateCalls(exec []byte, opts Options) ([]string, int) { } return res } + nonfailPre, nonfailPost := "", "" + if opts.HandleSegv { + nonfailPre, nonfailPost = "NONFAILING(", ")" + } lastCall := 0 seenCall := false var calls []string @@ -221,12 +232,12 @@ loop: bfOff := read() bfLen := read() if bfOff == 0 && bfLen == 0 { - fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = (uint%v_t)0x%x);\n", size*8, addr, size*8, arg) + fmt.Fprintf(w, "\t%s*(uint%v_t*)0x%x = (uint%v_t)0x%x%s;\n", nonfailPre, size*8, addr, size*8, arg, nonfailPost) } else { - fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v_t, 0x%x, 0x%x, %v, %v));\n", size*8, addr, arg, bfOff, bfLen) + fmt.Fprintf(w, "\t%sSTORE_BY_BITMASK(uint%v_t, 0x%x, 0x%x, %v, %v)%s;\n", nonfailPre, size*8, addr, arg, bfOff, bfLen, nonfailPost) } case prog.ExecArgResult: - fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n", size*8, addr, resultRef()) + fmt.Fprintf(w, "\t%s*(uint%v_t*)0x%x = %v%s;\n", nonfailPre, size*8, addr, resultRef(), nonfailPost) case prog.ExecArgData: data := exec[:size] exec = exec[(size+7)/8*8:] @@ -240,7 +251,7 @@ loop: } esc = append(esc, '\\', 'x', hex(v>>4), hex(v<<4>>4)) } - fmt.Fprintf(w, "\tNONFAILING(memcpy((void*)0x%x, \"%s\", %v));\n", addr, esc, size) + fmt.Fprintf(w, "\t%smemcpy((void*)0x%x, \"%s\", %v)%s;\n", nonfailPre, addr, esc, size, nonfailPost) case prog.ExecArgCsum: csum_kind := read() switch csum_kind { @@ -254,7 +265,7 @@ loop: chunk_size := read() switch chunk_kind { case prog.ExecArgCsumChunkData: - fmt.Fprintf(w, "\tNONFAILING(csum_inet_update(&csum_%d, (const uint8_t*)0x%x, %d));\n", n, chunk_value, chunk_size) + fmt.Fprintf(w, "\t%scsum_inet_update(&csum_%d, (const uint8_t*)0x%x, %d)%s;\n", nonfailPre, n, chunk_value, chunk_size, nonfailPost) case prog.ExecArgCsumChunkConst: fmt.Fprintf(w, "\tuint%d_t csum_%d_chunk_%d = 0x%x;\n", chunk_size*8, n, i, chunk_value) fmt.Fprintf(w, "\tcsum_inet_update(&csum_%d, (const uint8_t*)&csum_%d_chunk_%d, %d);\n", n, n, i, chunk_size) @@ -262,7 +273,7 @@ loop: panic(fmt.Sprintf("unknown checksum chunk kind %v", chunk_kind)) } } - fmt.Fprintf(w, "\tNONFAILING(*(uint16_t*)0x%x = csum_inet_digest(&csum_%d));\n", addr, n) + fmt.Fprintf(w, "\t%s*(uint16_t*)0x%x = csum_inet_digest(&csum_%d)%s;\n", nonfailPre, addr, n, nonfailPost) default: panic(fmt.Sprintf("unknown csum kind %v", csum_kind)) } @@ -273,7 +284,7 @@ loop: addr := read() size := read() fmt.Fprintf(w, "\tif (r[%v] != -1)\n", lastCall) - fmt.Fprintf(w, "\t\tNONFAILING(r[%v] = *(uint%v_t*)0x%x);\n", n, size*8, addr) + fmt.Fprintf(w, "\t\t%sr[%v] = *(uint%v_t*)0x%x%s;\n", nonfailPre, n, size*8, addr, nonfailPost) default: // Normal syscall. newCall() @@ -337,6 +348,9 @@ func preprocessCommonHeader(opts Options, handled map[string]int) (string, error if opts.UseTmpDir { defines = append(defines, "SYZ_USE_TMP_DIR") } + if opts.HandleSegv { + defines = append(defines, "SYZ_HANDLE_SEGV") + } for name, _ := range handled { defines = append(defines, "__NR_"+name) } diff --git a/csource/csource_test.go b/csource/csource_test.go index 3e09a3019..dbecec54c 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -38,16 +38,18 @@ func allOptionsPermutations() []Options { for _, opt.Fault = range []bool{false, true} { for _, opt.EnableTun = range []bool{false, true} { for _, opt.UseTmpDir = range []bool{false, true} { - if opt.Collide && !opt.Threaded { - continue + for _, opt.HandleSegv = range []bool{false, true} { + if opt.Collide && !opt.Threaded { + continue + } + if !opt.Repeat && opt.Procs != 1 { + continue + } + if testing.Short() && opt.Procs != 1 { + continue + } + options = append(options, opt) } - if !opt.Repeat && opt.Procs != 1 { - continue - } - if testing.Short() && opt.Procs != 1 { - continue - } - options = append(options, opt) } } } diff --git a/executor/common.h b/executor/common.h index 5041aaf7b..032365471 100644 --- a/executor/common.h +++ b/executor/common.h @@ -132,6 +132,7 @@ void debug(const char* msg, ...) fflush(stdout); } +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) __thread int skip_segv; __thread jmp_buf segv_env; @@ -175,6 +176,16 @@ static void install_segv_handler() 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_USE_TMP_DIR) static void use_temporary_dir() { @@ -189,15 +200,6 @@ static void use_temporary_dir() } #endif -#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); \ - } - #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)) @@ -469,8 +471,13 @@ static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2) } struct tcp_resources* res = (struct tcp_resources*)a0; +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) NONFAILING(res->seq = htonl((ntohl(tcphdr->seq) + (uint32_t)a1))); NONFAILING(res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32_t)a2))); +#else + res->seq = htonl((ntohl(tcphdr->seq) + (uint32_t)a1)); + res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32_t)a2)); +#endif debug("extracted seq: %08x\n", res->seq); debug("extracted ack: %08x\n", res->ack); @@ -492,7 +499,11 @@ static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2) // syz_open_dev(dev strconst, id intptr, flags flags[open_flags]) fd char buf[1024]; char* hash; +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) NONFAILING(strncpy(buf, (char*)a0, sizeof(buf))); +#else + strncpy(buf, (char*)a0, sizeof(buf)); +#endif buf[sizeof(buf) - 1] = 0; while ((hash = strchr(buf, '#'))) { *hash = '0' + (char)(a1 % 10); // 10 devices should be enough for everyone. diff --git a/executor/common_kvm_amd64.h b/executor/common_kvm_amd64.h index dd37733ed..e4753223e 100644 --- a/executor/common_kvm_amd64.h +++ b/executor/common_kvm_amd64.h @@ -7,6 +7,15 @@ // See Intel Software Developer’s Manual Volume 3: System Programming Guide // for details on what happens here. +// We could put each NONFAILING use in this file under ifdef, +// but I don't think it's worth it. +#ifndef NONFAILING +#define NONFAILING(x) \ + { \ + x; \ + } +#endif + #include "kvm.S.h" #include "kvm.h" diff --git a/repro/repro.go b/repro/repro.go index 3ae553bac..f4cfde322 100644 --- a/repro/repro.go +++ b/repro/repro.go @@ -151,14 +151,15 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er } Logf(2, "reproducing crash '%v': suspecting %v programs", ctx.crashDesc, len(suspected)) opts := csource.Options{ - Threaded: true, - Collide: true, - Repeat: true, - Procs: ctx.cfg.Procs, - Sandbox: ctx.cfg.Sandbox, - EnableTun: true, - UseTmpDir: true, - Repro: true, + Threaded: true, + Collide: true, + Repeat: true, + Procs: ctx.cfg.Procs, + Sandbox: ctx.cfg.Sandbox, + EnableTun: true, + UseTmpDir: true, + HandleSegv: true, + Repro: true, } // Execute the suspected programs. // We first try to execute each program for 10 seconds, that should detect simple crashes @@ -299,6 +300,17 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er res.Opts = opts } } + if res.Opts.HandleSegv { + opts = res.Opts + opts.HandleSegv = false + crashed, err := ctx.testCProg(res.Prog, duration, opts) + if err != nil { + return res, err + } + if crashed { + res.Opts = opts + } + } return res, nil } diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go index 878772d42..1d2007755 100644 --- a/tools/syz-prog2c/prog2c.go +++ b/tools/syz-prog2c/prog2c.go @@ -14,16 +14,17 @@ import ( ) var ( - flagThreaded = flag.Bool("threaded", false, "create threaded program") - flagCollide = flag.Bool("collide", false, "create collide program") - flagRepeat = flag.Bool("repeat", false, "repeat program infinitely or not") - flagProcs = flag.Int("procs", 4, "number of parallel processes") - flagSandbox = flag.String("sandbox", "none", "sandbox to use (none, setuid, namespace)") - flagProg = flag.String("prog", "", "file with program to convert (required)") - flagFaultCall = flag.Int("fault_call", -1, "inject fault into this call (0-based)") - flagFaultNth = flag.Int("fault_nth", 0, "inject fault on n-th operation (0-based)") - flagEnableTun = flag.Bool("tun", false, "set up TUN/TAP interface") - flagUseTmpDir = flag.Bool("tmpdir", false, "create a temporary dir and execute inside it") + flagThreaded = flag.Bool("threaded", false, "create threaded program") + flagCollide = flag.Bool("collide", false, "create collide program") + flagRepeat = flag.Bool("repeat", false, "repeat program infinitely or not") + flagProcs = flag.Int("procs", 4, "number of parallel processes") + flagSandbox = flag.String("sandbox", "none", "sandbox to use (none, setuid, namespace)") + flagProg = flag.String("prog", "", "file with program to convert (required)") + flagFaultCall = flag.Int("fault_call", -1, "inject fault into this call (0-based)") + flagFaultNth = flag.Int("fault_nth", 0, "inject fault on n-th operation (0-based)") + flagEnableTun = flag.Bool("tun", false, "set up TUN/TAP interface") + flagUseTmpDir = flag.Bool("tmpdir", false, "create a temporary dir and execute inside it") + flagHandleSegv = flag.Bool("segv", false, "catch and ignore SIGSEGV") ) func main() { @@ -43,17 +44,18 @@ func main() { os.Exit(1) } opts := csource.Options{ - Threaded: *flagThreaded, - Collide: *flagCollide, - Repeat: *flagRepeat, - Procs: *flagProcs, - Sandbox: *flagSandbox, - Fault: *flagFaultCall >= 0, - FaultCall: *flagFaultCall, - FaultNth: *flagFaultNth, - EnableTun: *flagEnableTun, - UseTmpDir: *flagUseTmpDir, - Repro: false, + Threaded: *flagThreaded, + Collide: *flagCollide, + Repeat: *flagRepeat, + Procs: *flagProcs, + Sandbox: *flagSandbox, + Fault: *flagFaultCall >= 0, + FaultCall: *flagFaultCall, + FaultNth: *flagFaultNth, + EnableTun: *flagEnableTun, + UseTmpDir: *flagUseTmpDir, + HandleSegv: *flagHandleSegv, + Repro: false, } src, err := csource.Write(p, opts) if err != nil { -- cgit mrf-deployment From 73a895df6168bc12559d1fa16aae7e52646d7ec3 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 18 May 2017 17:03:02 +0200 Subject: csource: use sandbox only when required --- csource/common.go | 2 ++ csource/csource.go | 41 ++++++++++++++++++++++++++++++++--------- csource/csource_test.go | 2 +- executor/common.h | 2 ++ repro/repro.go | 11 +++++++++++ tools/syz-prog2c/prog2c.go | 2 +- 6 files changed, 49 insertions(+), 11 deletions(-) (limited to 'csource/csource_test.go') diff --git a/csource/common.go b/csource/common.go index 3ac10334d..74f4aba35 100644 --- a/csource/common.go +++ b/csource/common.go @@ -1556,6 +1556,7 @@ static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a } } +#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE) static void loop(); static void sandbox_common() @@ -1578,6 +1579,7 @@ static void sandbox_common() unshare(CLONE_NEWIPC); unshare(CLONE_IO); } +#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) static int do_sandbox_none(int executor_pid, bool enable_tun) diff --git a/csource/csource.go b/csource/csource.go index 8faae8e5e..603cb37f5 100644 --- a/csource/csource.go +++ b/csource/csource.go @@ -86,9 +86,16 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { if opts.UseTmpDir { fmt.Fprintf(w, "\tuse_temporary_dir();\n") } - 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") + 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") + } else { + if opts.EnableTun { + fmt.Fprintf(w, "\tsetup_tun(0, %v);\n", opts.EnableTun) + } + fmt.Fprint(w, "\tloop();\n") + } fmt.Fprint(w, "\treturn 0;\n}\n") } else { generateTestFunc(w, opts, calls, "test") @@ -100,9 +107,16 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { if opts.UseTmpDir { fmt.Fprintf(w, "\tuse_temporary_dir();\n") } - 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") + 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") + } else { + if opts.EnableTun { + fmt.Fprintf(w, "\tsetup_tun(0, %v);\n", opts.EnableTun) + } + fmt.Fprint(w, "\tloop();\n") + } fmt.Fprint(w, "\treturn 0;\n}\n") } else { fmt.Fprint(w, "int main()\n{\n") @@ -115,9 +129,16 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { if opts.UseTmpDir { fmt.Fprintf(w, "\t\t\tuse_temporary_dir();\n") } - 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") + 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") + } else { + if opts.EnableTun { + fmt.Fprintf(w, "\t\t\tsetup_tun(i, %v);\n", opts.EnableTun) + } + fmt.Fprint(w, "\t\t\tloop();\n") + } fmt.Fprint(w, "\t\t\treturn 0;\n") fmt.Fprint(w, "\t\t}\n") fmt.Fprint(w, "\t}\n") @@ -334,6 +355,8 @@ func preprocessCommonHeader(opts Options, handled map[string]int, useBitmasks bo defines = append(defines, "SYZ_USE_BITMASKS") } switch opts.Sandbox { + case "": + // No sandbox, do nothing. case "none": defines = append(defines, "SYZ_SANDBOX_NONE") case "setuid": diff --git a/csource/csource_test.go b/csource/csource_test.go index dbecec54c..ca39b162a 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -33,7 +33,7 @@ func allOptionsPermutations() []Options { for _, opt.Collide = range []bool{false, true} { for _, opt.Repeat = range []bool{false, true} { for _, opt.Procs = range []int{1, 4} { - for _, opt.Sandbox = range []string{"none", "setuid", "namespace"} { + for _, opt.Sandbox = range []string{"", "none", "setuid", "namespace"} { for _, opt.Repro = range []bool{false, true} { for _, opt.Fault = range []bool{false, true} { for _, opt.EnableTun = range []bool{false, true} { diff --git a/executor/common.h b/executor/common.h index 609bab1c8..4ee1cd140 100644 --- a/executor/common.h +++ b/executor/common.h @@ -644,6 +644,7 @@ static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a } } +#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE) static void loop(); static void sandbox_common() @@ -667,6 +668,7 @@ static void sandbox_common() unshare(CLONE_NEWIPC); unshare(CLONE_IO); } +#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) static int do_sandbox_none(int executor_pid, bool enable_tun) diff --git a/repro/repro.go b/repro/repro.go index e6ab35cc3..d6d46eff3 100644 --- a/repro/repro.go +++ b/repro/repro.go @@ -289,6 +289,17 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er res.Opts = opts } } + if res.Opts.Sandbox != "" { + opts = res.Opts + opts.Sandbox = "" + crashed, err := ctx.testCProg(res.Prog, duration, opts) + if err != nil { + return res, err + } + if crashed { + res.Opts = opts + } + } if res.Opts.UseTmpDir { opts = res.Opts opts.UseTmpDir = false diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go index 1d2007755..75a5126e3 100644 --- a/tools/syz-prog2c/prog2c.go +++ b/tools/syz-prog2c/prog2c.go @@ -18,7 +18,7 @@ var ( flagCollide = flag.Bool("collide", false, "create collide program") flagRepeat = flag.Bool("repeat", false, "repeat program infinitely or not") flagProcs = flag.Int("procs", 4, "number of parallel processes") - flagSandbox = flag.String("sandbox", "none", "sandbox to use (none, setuid, namespace)") + flagSandbox = flag.String("sandbox", "", "sandbox to use (none, setuid, namespace)") flagProg = flag.String("prog", "", "file with program to convert (required)") flagFaultCall = flag.Int("fault_call", -1, "inject fault into this call (0-based)") flagFaultNth = flag.Int("fault_nth", 0, "inject fault on n-th operation (0-based)") -- cgit mrf-deployment From c99b02d2248fbdcd6f44037326b16c928f4423f1 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 18 May 2017 18:17:16 +0200 Subject: csource: try to simplify repeat loop --- csource/common.go | 13 ++++++++++--- csource/csource.go | 4 ++++ csource/csource_test.go | 23 ++++++++++++++--------- executor/common.h | 13 ++++++++++--- repro/repro.go | 12 ++++++++++++ tools/syz-prog2c/prog2c.go | 2 ++ 6 files changed, 52 insertions(+), 15 deletions(-) (limited to 'csource/csource_test.go') diff --git a/csource/common.go b/csource/common.go index 74f4aba35..b4d3f0a33 100644 --- a/csource/common.go +++ b/csource/common.go @@ -1728,7 +1728,7 @@ static int do_sandbox_namespace(int executor_pid, bool enable_tun) } #endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) static void remove_dir(const char* dir) { DIR* dp; @@ -1797,9 +1797,7 @@ retry: exitf("rmdir(%s) failed", dir); } } -#endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT) static uint64_t current_time_ms() { struct timespec ts; @@ -1830,6 +1828,7 @@ static int inject_fault(int nth) #if defined(SYZ_REPEAT) static void test(); +#if defined(SYZ_WAIT_REPEAT) void loop() { int iter; @@ -1870,5 +1869,13 @@ void loop() remove_dir(cwdbuf); } } +#else +void loop() +{ + while (1) { + test(); + } +} +#endif #endif ` diff --git a/csource/csource.go b/csource/csource.go index 603cb37f5..ae3e54df8 100644 --- a/csource/csource.go +++ b/csource/csource.go @@ -36,6 +36,7 @@ type Options struct { EnableTun bool UseTmpDir bool HandleSegv bool + WaitRepeat bool // Generate code for use with repro package to prints log messages, // which allows to distinguish between a hang and an absent crash. @@ -381,6 +382,9 @@ func preprocessCommonHeader(opts Options, handled map[string]int, useBitmasks bo if opts.HandleSegv { defines = append(defines, "SYZ_HANDLE_SEGV") } + if opts.WaitRepeat { + defines = append(defines, "SYZ_WAIT_REPEAT") + } for name, _ := range handled { defines = append(defines, "__NR_"+name) } diff --git a/csource/csource_test.go b/csource/csource_test.go index ca39b162a..097e014ec 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -39,16 +39,21 @@ func allOptionsPermutations() []Options { for _, opt.EnableTun = range []bool{false, true} { for _, opt.UseTmpDir = range []bool{false, true} { for _, opt.HandleSegv = range []bool{false, true} { - if opt.Collide && !opt.Threaded { - continue + for _, opt.WaitRepeat = range []bool{false, true} { + if opt.Collide && !opt.Threaded { + continue + } + if !opt.Repeat && opt.Procs != 1 { + continue + } + if !opt.Repeat && opt.WaitRepeat { + continue + } + if testing.Short() && opt.Procs != 1 { + continue + } + options = append(options, opt) } - if !opt.Repeat && opt.Procs != 1 { - continue - } - if testing.Short() && opt.Procs != 1 { - continue - } - options = append(options, opt) } } } diff --git a/executor/common.h b/executor/common.h index 4ee1cd140..6e4955fab 100644 --- a/executor/common.h +++ b/executor/common.h @@ -827,7 +827,7 @@ static int do_sandbox_namespace(int executor_pid, bool enable_tun) } #endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) // One does not simply remove a directory. // There can be mounts, so we need to try to umount. // Moreover, a mount can be mounted several times, so we need to try to umount in a loop. @@ -904,9 +904,7 @@ retry: exitf("rmdir(%s) failed", dir); } } -#endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT) static uint64_t current_time_ms() { struct timespec ts; @@ -937,6 +935,7 @@ static int inject_fault(int nth) #if defined(SYZ_REPEAT) static void test(); +#if defined(SYZ_WAIT_REPEAT) void loop() { int iter; @@ -977,4 +976,12 @@ void loop() remove_dir(cwdbuf); } } +#else +void loop() +{ + while (1) { + test(); + } +} +#endif #endif diff --git a/repro/repro.go b/repro/repro.go index d6d46eff3..23d59856d 100644 --- a/repro/repro.go +++ b/repro/repro.go @@ -159,6 +159,7 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er EnableTun: true, UseTmpDir: true, HandleSegv: true, + WaitRepeat: true, Repro: true, } // Execute the suspected programs. @@ -322,6 +323,17 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er res.Opts = opts } } + if res.Opts.WaitRepeat { + opts = res.Opts + opts.WaitRepeat = false + crashed, err := ctx.testCProg(res.Prog, duration, opts) + if err != nil { + return res, err + } + if crashed { + res.Opts = opts + } + } return res, nil } diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go index 75a5126e3..4eadb6377 100644 --- a/tools/syz-prog2c/prog2c.go +++ b/tools/syz-prog2c/prog2c.go @@ -25,6 +25,7 @@ var ( flagEnableTun = flag.Bool("tun", false, "set up TUN/TAP interface") flagUseTmpDir = flag.Bool("tmpdir", false, "create a temporary dir and execute inside it") flagHandleSegv = flag.Bool("segv", false, "catch and ignore SIGSEGV") + flagWaitRepeat = flag.Bool("waitrepeat", false, "wait for each repeat attempt") ) func main() { @@ -55,6 +56,7 @@ func main() { EnableTun: *flagEnableTun, UseTmpDir: *flagUseTmpDir, HandleSegv: *flagHandleSegv, + WaitRepeat: *flagWaitRepeat, Repro: false, } src, err := csource.Write(p, opts) -- cgit mrf-deployment From 120e26c2fecf4fcabc18af43329171d6afba02b4 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 18 May 2017 19:18:26 +0200 Subject: csourse: don't generate debug printfs --- csource/common.go | 34 ++++++++++++++++++++++++++++++++-- csource/csource.go | 4 ++++ csource/csource_test.go | 26 ++++++++++++++------------ executor/common.h | 34 ++++++++++++++++++++++++++++++++-- repro/repro.go | 12 ++++++++++++ tools/syz-prog2c/prog2c.go | 2 ++ 6 files changed, 96 insertions(+), 16 deletions(-) (limited to 'csource/csource_test.go') diff --git a/csource/common.go b/csource/common.go index b4d3f0a33..d4d6890f0 100644 --- a/csource/common.go +++ b/csource/common.go @@ -103,6 +103,7 @@ __attribute__((noreturn)) void exitf(const char* msg, ...) doexit(kRetryStatus); } +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) static int flag_debug; void debug(const char* msg, ...) @@ -115,6 +116,7 @@ void debug(const char* msg, ...) va_end(args); fflush(stdout); } +#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_BITMASKS) #define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1) @@ -142,10 +144,14 @@ static void segv_handler(int sig, siginfo_t* info, void* uctx) 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)) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("SIGSEGV on %p, skipping\n", addr); +#endif _longjmp(segv_env, 1); } +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("SIGSEGV on %p, exiting\n", addr); +#endif doexit(sig); for (;;) { } @@ -298,8 +304,10 @@ static void setup_tun(uint64_t pid, bool enable_tun) if (enable_tun) initialize_tun(pid); } +#endif -int read_tun(char* data, int size) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_TUN_ENABLE) && (defined(__NR_syz_extract_tcp_res) || defined(SYZ_REPEAT))) +static int read_tun(char* data, int size) { int rv = read(tunfd, data, size); if (rv < 0) { @@ -309,8 +317,10 @@ int read_tun(char* data, int size) } return rv; } +#endif -void debug_dump_data(const char* data, int length) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_DEBUG) && defined(SYZ_TUN_ENABLE) && (defined(__NR_syz_emit_ethernet) || defined(__NR_syz_extract_tcp_res))) +static void debug_dump_data(const char* data, int length) { int i; for (i = 0; i < length; i++) { @@ -364,7 +374,9 @@ static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1) int64_t length = a0; char* data = (char*)a1; +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug_dump_data(data, length); +#endif return write(tunfd, data, length); } #endif @@ -408,7 +420,9 @@ static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2) if (rv == -1) return (uintptr_t)-1; size_t length = rv; +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug_dump_data(data, length); +#endif struct tcphdr* tcphdr; @@ -445,8 +459,10 @@ static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2) res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32_t)a2)); #endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("extracted seq: %08x\n", res->seq); debug("extracted ack: %08x\n", res->ack); +#endif return 0; } @@ -1686,7 +1702,9 @@ static int namespace_sandbox_proc(void* arg) if (mkdir("./syz-tmp/pivot", 0777)) fail("mkdir failed"); if (syscall(SYS_pivot_root, "./syz-tmp", "./syz-tmp/pivot")) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("pivot_root failed"); +#endif if (chdir("./syz-tmp")) fail("chdir failed"); } else { @@ -1756,16 +1774,22 @@ retry: } int i; for (i = 0;; i++) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("unlink(%s)\n", filename); +#endif if (unlink(filename) == 0) break; if (errno == EROFS) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("ignoring EROFS\n"); +#endif break; } if (errno != EBUSY || i > 100) exitf("unlink(%s) failed", filename); +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("umount(%s)\n", filename); +#endif if (umount2(filename, MNT_DETACH)) exitf("umount(%s) failed", filename); } @@ -1773,16 +1797,22 @@ retry: closedir(dp); int i; for (i = 0;; i++) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("rmdir(%s)\n", dir); +#endif if (rmdir(dir) == 0) break; if (i < 100) { if (errno == EROFS) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("ignoring EROFS\n"); +#endif break; } if (errno == EBUSY) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("umount(%s)\n", dir); +#endif if (umount2(dir, MNT_DETACH)) exitf("umount(%s) failed", dir); continue; diff --git a/csource/csource.go b/csource/csource.go index ae3e54df8..3eeb369dc 100644 --- a/csource/csource.go +++ b/csource/csource.go @@ -37,6 +37,7 @@ type Options struct { UseTmpDir bool HandleSegv bool WaitRepeat bool + Debug bool // Generate code for use with repro package to prints log messages, // which allows to distinguish between a hang and an absent crash. @@ -385,6 +386,9 @@ func preprocessCommonHeader(opts Options, handled map[string]int, useBitmasks bo if opts.WaitRepeat { defines = append(defines, "SYZ_WAIT_REPEAT") } + if opts.Debug { + defines = append(defines, "SYZ_DEBUG") + } for name, _ := range handled { defines = append(defines, "__NR_"+name) } diff --git a/csource/csource_test.go b/csource/csource_test.go index 097e014ec..7b68954f3 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -40,19 +40,21 @@ func allOptionsPermutations() []Options { for _, opt.UseTmpDir = range []bool{false, true} { for _, opt.HandleSegv = range []bool{false, true} { for _, opt.WaitRepeat = range []bool{false, true} { - if opt.Collide && !opt.Threaded { - continue + for _, opt.Debug = range []bool{false, true} { + if opt.Collide && !opt.Threaded { + continue + } + if !opt.Repeat && opt.Procs != 1 { + continue + } + if !opt.Repeat && opt.WaitRepeat { + continue + } + if testing.Short() && opt.Procs != 1 { + continue + } + options = append(options, opt) } - if !opt.Repeat && opt.Procs != 1 { - continue - } - if !opt.Repeat && opt.WaitRepeat { - continue - } - if testing.Short() && opt.Procs != 1 { - continue - } - options = append(options, opt) } } } diff --git a/executor/common.h b/executor/common.h index 6e4955fab..57ff0d95b 100644 --- a/executor/common.h +++ b/executor/common.h @@ -119,6 +119,7 @@ __attribute__((noreturn)) void exitf(const char* msg, ...) doexit(kRetryStatus); } +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) static int flag_debug; void debug(const char* msg, ...) @@ -131,6 +132,7 @@ void debug(const char* msg, ...) va_end(args); fflush(stdout); } +#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_BITMASKS) #define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1) @@ -164,10 +166,14 @@ static void segv_handler(int sig, siginfo_t* info, void* uctx) 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)) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("SIGSEGV on %p, skipping\n", addr); +#endif _longjmp(segv_env, 1); } +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("SIGSEGV on %p, exiting\n", addr); +#endif doexit(sig); for (;;) { } @@ -329,8 +335,10 @@ static void setup_tun(uint64_t pid, bool enable_tun) if (enable_tun) initialize_tun(pid); } +#endif -int read_tun(char* data, int size) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_TUN_ENABLE) && (defined(__NR_syz_extract_tcp_res) || defined(SYZ_REPEAT))) +static int read_tun(char* data, int size) { int rv = read(tunfd, data, size); if (rv < 0) { @@ -340,8 +348,10 @@ int read_tun(char* data, int size) } return rv; } +#endif -void debug_dump_data(const char* data, int length) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_DEBUG) && defined(SYZ_TUN_ENABLE) && (defined(__NR_syz_emit_ethernet) || defined(__NR_syz_extract_tcp_res))) +static void debug_dump_data(const char* data, int length) { int i; for (i = 0; i < length; i++) { @@ -396,7 +406,9 @@ static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1) int64_t length = a0; char* data = (char*)a1; +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug_dump_data(data, length); +#endif return write(tunfd, data, length); } #endif @@ -443,7 +455,9 @@ static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2) if (rv == -1) return (uintptr_t)-1; size_t length = rv; +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug_dump_data(data, length); +#endif struct tcphdr* tcphdr; @@ -481,8 +495,10 @@ static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2) res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32_t)a2)); #endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("extracted seq: %08x\n", res->seq); debug("extracted ack: %08x\n", res->ack); +#endif return 0; } @@ -781,7 +797,9 @@ static int namespace_sandbox_proc(void* arg) if (mkdir("./syz-tmp/pivot", 0777)) fail("mkdir failed"); if (syscall(SYS_pivot_root, "./syz-tmp", "./syz-tmp/pivot")) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("pivot_root failed"); +#endif if (chdir("./syz-tmp")) fail("chdir failed"); } else { @@ -863,16 +881,22 @@ retry: } int i; for (i = 0;; i++) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("unlink(%s)\n", filename); +#endif if (unlink(filename) == 0) break; if (errno == EROFS) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("ignoring EROFS\n"); +#endif break; } if (errno != EBUSY || i > 100) exitf("unlink(%s) failed", filename); +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("umount(%s)\n", filename); +#endif if (umount2(filename, MNT_DETACH)) exitf("umount(%s) failed", filename); } @@ -880,16 +904,22 @@ retry: closedir(dp); int i; for (i = 0;; i++) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("rmdir(%s)\n", dir); +#endif if (rmdir(dir) == 0) break; if (i < 100) { if (errno == EROFS) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("ignoring EROFS\n"); +#endif break; } if (errno == EBUSY) { +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) debug("umount(%s)\n", dir); +#endif if (umount2(dir, MNT_DETACH)) exitf("umount(%s) failed", dir); continue; diff --git a/repro/repro.go b/repro/repro.go index 23d59856d..4101da1ae 100644 --- a/repro/repro.go +++ b/repro/repro.go @@ -160,6 +160,7 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er UseTmpDir: true, HandleSegv: true, WaitRepeat: true, + Debug: true, Repro: true, } // Execute the suspected programs. @@ -334,6 +335,17 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er res.Opts = opts } } + if res.Opts.Debug { + opts = res.Opts + opts.Debug = false + crashed, err := ctx.testCProg(res.Prog, duration, opts) + if err != nil { + return res, err + } + if crashed { + res.Opts = opts + } + } return res, nil } diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go index 4eadb6377..e3089c3ce 100644 --- a/tools/syz-prog2c/prog2c.go +++ b/tools/syz-prog2c/prog2c.go @@ -26,6 +26,7 @@ var ( flagUseTmpDir = flag.Bool("tmpdir", false, "create a temporary dir and execute inside it") flagHandleSegv = flag.Bool("segv", false, "catch and ignore SIGSEGV") flagWaitRepeat = flag.Bool("waitrepeat", false, "wait for each repeat attempt") + flagDebug = flag.Bool("debug", false, "generate debug printfs") ) func main() { @@ -57,6 +58,7 @@ func main() { UseTmpDir: *flagUseTmpDir, HandleSegv: *flagHandleSegv, WaitRepeat: *flagWaitRepeat, + Debug: *flagDebug, Repro: false, } src, err := csource.Write(p, opts) -- cgit mrf-deployment From ae0e4fa356443c8b77174d2ec5986645ea409b14 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Tue, 30 May 2017 14:39:27 +0200 Subject: csource: speed up short tests --- csource/csource_test.go | 80 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 7 deletions(-) (limited to 'csource/csource_test.go') diff --git a/csource/csource_test.go b/csource/csource_test.go index 7b68954f3..e9ab1d993 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -16,16 +16,55 @@ import ( func initTest(t *testing.T) (rand.Source, int) { t.Parallel() - iters := 10 - if testing.Short() { - iters = 1 - } + iters := 1 seed := int64(time.Now().UnixNano()) rs := rand.NewSource(seed) t.Logf("seed=%v", seed) return rs, iters } +func allOptionsSingle() []Options { + var options []Options + var opt Options + for _, opt.Threaded = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.Collide = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.Repeat = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.Procs = range []int{1, 4} { + options = append(options, opt) + } + for _, opt.Sandbox = range []string{"", "none", "setuid", "namespace"} { + options = append(options, opt) + } + for _, opt.Repro = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.Fault = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.EnableTun = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.UseTmpDir = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.HandleSegv = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.WaitRepeat = range []bool{false, true} { + options = append(options, opt) + } + for _, opt.Debug = range []bool{false, true} { + options = append(options, opt) + } + return options +} + func allOptionsPermutations() []Options { var options []Options var opt Options @@ -69,7 +108,7 @@ func allOptionsPermutations() []Options { return options } -func TestSyz(t *testing.T) { +func TestOne(t *testing.T) { rs, _ := initTest(t) opts := Options{ Threaded: true, @@ -83,11 +122,38 @@ func TestSyz(t *testing.T) { testOne(t, p, opts) } -func Test(t *testing.T) { +func TestOptionsSingle(t *testing.T) { rs, _ := initTest(t) syzProg := prog.GenerateAllSyzProg(rs) t.Logf("syz program:\n%s\n", syzProg.Serialize()) - for i, opts := range allOptionsPermutations() { + for i, opts := range allOptionsSingle() { + t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { + rs, iters := initTest(t) + t.Logf("opts: %+v", opts) + for i := 0; i < iters; i++ { + p := prog.Generate(rs, 10, nil) + testOne(t, p, opts) + } + testOne(t, syzProg, opts) + }) + } +} + +func TestOptionsPermutations(t *testing.T) { + rs, _ := initTest(t) + syzProg := prog.GenerateAllSyzProg(rs) + t.Logf("syz program:\n%s\n", syzProg.Serialize()) + allPermutations := allOptionsPermutations() + var permutations []Options + if testing.Short() { + r := rand.New(rs) + for i := 0; i < 32; i++ { + permutations = append(permutations, allPermutations[r.Intn(len(allPermutations)-1)]) + } + } else { + permutations = allPermutations + } + for i, opts := range permutations { t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { rs, iters := initTest(t) t.Logf("opts: %+v", opts) -- cgit mrf-deployment From ebcd9ade3f2d3098f069dcc0a0f093ca7b3ed6b1 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Tue, 6 Jun 2017 18:13:52 +0200 Subject: csource: use reflect to iterate over options --- csource/csource_test.go | 145 ++++++++++++++++-------------------------------- 1 file changed, 48 insertions(+), 97 deletions(-) (limited to 'csource/csource_test.go') diff --git a/csource/csource_test.go b/csource/csource_test.go index e9ab1d993..7db490444 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -7,6 +7,7 @@ import ( "fmt" "math/rand" "os" + "reflect" "testing" "time" @@ -23,89 +24,56 @@ func initTest(t *testing.T) (rand.Source, int) { return rs, iters } -func allOptionsSingle() []Options { - var options []Options - var opt Options - for _, opt.Threaded = range []bool{false, true} { - options = append(options, opt) - } - for _, opt.Collide = range []bool{false, true} { - options = append(options, opt) - } - for _, opt.Repeat = range []bool{false, true} { - options = append(options, opt) - } - for _, opt.Procs = range []int{1, 4} { - options = append(options, opt) - } - for _, opt.Sandbox = range []string{"", "none", "setuid", "namespace"} { - options = append(options, opt) - } - for _, opt.Repro = range []bool{false, true} { - options = append(options, opt) - } - for _, opt.Fault = range []bool{false, true} { - options = append(options, opt) - } - for _, opt.EnableTun = range []bool{false, true} { - options = append(options, opt) - } - for _, opt.UseTmpDir = range []bool{false, true} { - options = append(options, opt) - } - for _, opt.HandleSegv = range []bool{false, true} { - options = append(options, opt) - } - for _, opt.WaitRepeat = range []bool{false, true} { - options = append(options, opt) +func enumerateField(opt Options, field int) []Options { + var opts []Options + s := reflect.ValueOf(&opt).Elem() + fldName := s.Type().Field(field).Name + fld := s.Field(field) + if fldName == "Sandbox" { + for _, sandbox := range []string{"", "none", "setuid", "namespace"} { + fld.SetString(sandbox) + opts = append(opts, opt) + } + } else if fldName == "Procs" { + for _, procs := range []int64{1, 4} { + fld.SetInt(procs) + opts = append(opts, opt) + } + } else if fldName == "FaultCall" { + opts = append(opts, opt) + } else if fldName == "FaultNth" { + opts = append(opts, opt) + } else if fld.Kind() == reflect.Bool { + for _, v := range []bool{false, true} { + fld.SetBool(v) + opts = append(opts, opt) + } + } else { + panic(fmt.Sprintf("field '%v' is not boolean", fldName)) } - for _, opt.Debug = range []bool{false, true} { - options = append(options, opt) + return opts +} + +func allOptionsSingle() []Options { + var opts []Options + fields := reflect.TypeOf(Options{}).NumField() + for i := 0; i < fields; i++ { + opts = append(opts, enumerateField(Options{}, i)...) } - return options + return opts } func allOptionsPermutations() []Options { - var options []Options - var opt Options - for _, opt.Threaded = range []bool{false, true} { - for _, opt.Collide = range []bool{false, true} { - for _, opt.Repeat = range []bool{false, true} { - for _, opt.Procs = range []int{1, 4} { - for _, opt.Sandbox = range []string{"", "none", "setuid", "namespace"} { - for _, opt.Repro = range []bool{false, true} { - for _, opt.Fault = range []bool{false, true} { - for _, opt.EnableTun = range []bool{false, true} { - for _, opt.UseTmpDir = range []bool{false, true} { - for _, opt.HandleSegv = range []bool{false, true} { - for _, opt.WaitRepeat = range []bool{false, true} { - for _, opt.Debug = range []bool{false, true} { - if opt.Collide && !opt.Threaded { - continue - } - if !opt.Repeat && opt.Procs != 1 { - continue - } - if !opt.Repeat && opt.WaitRepeat { - continue - } - if testing.Short() && opt.Procs != 1 { - continue - } - options = append(options, opt) - } - } - } - } - } - } - } - } - } - } + opts := []Options{ Options{} } + fields := reflect.TypeOf(Options{}).NumField() + for i := 0; i < fields; i++ { + var newOpts []Options + for _, opt := range opts { + newOpts = append(newOpts, enumerateField(opt, i)...) } + opts = newOpts } - return options + return opts } func TestOne(t *testing.T) { @@ -122,36 +90,19 @@ func TestOne(t *testing.T) { testOne(t, p, opts) } -func TestOptionsSingle(t *testing.T) { - rs, _ := initTest(t) - syzProg := prog.GenerateAllSyzProg(rs) - t.Logf("syz program:\n%s\n", syzProg.Serialize()) - for i, opts := range allOptionsSingle() { - t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { - rs, iters := initTest(t) - t.Logf("opts: %+v", opts) - for i := 0; i < iters; i++ { - p := prog.Generate(rs, 10, nil) - testOne(t, p, opts) - } - testOne(t, syzProg, opts) - }) - } -} - -func TestOptionsPermutations(t *testing.T) { +func TestOptions(t *testing.T) { rs, _ := initTest(t) syzProg := prog.GenerateAllSyzProg(rs) t.Logf("syz program:\n%s\n", syzProg.Serialize()) + permutations := allOptionsSingle() allPermutations := allOptionsPermutations() - var permutations []Options if testing.Short() { r := rand.New(rs) for i := 0; i < 32; i++ { - permutations = append(permutations, allPermutations[r.Intn(len(allPermutations)-1)]) + permutations = append(permutations, allPermutations[r.Intn(len(allPermutations))]) } } else { - permutations = allPermutations + permutations = append(permutations, allPermutations...) } for i, opts := range permutations { t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { -- cgit mrf-deployment