diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-07-26 17:47:27 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-07-27 10:22:23 +0200 |
| commit | 9d92841b4e4d0ac0f97f983cd90087323f27c26c (patch) | |
| tree | 562c5d32f96e010c34b3f122616213110d1b979b | |
| parent | c3da5dc5e0d0c6614f48c2d1178d58ff1e47809c (diff) | |
pkg/csource: tidy generated code
1. Remove unnecessary includes.
2. Remove thunk function in threaded mode.
3. Inline syscalls into main for the simplest case.
4. Define main in common.h rather than form with printfs.
5. Fix generation for repeat mode
(we had 2 infinite loops: in main and in loop).
6. Remove unused functions (setup/reset_loop, setup/reset_test,
sandbox_namespace, etc).
| -rw-r--r-- | executor/common.h | 107 | ||||
| -rw-r--r-- | executor/common_akaros.h | 9 | ||||
| -rw-r--r-- | executor/common_bsd.h | 6 | ||||
| -rw-r--r-- | executor/common_fuchsia.h | 3 | ||||
| -rw-r--r-- | executor/common_linux.h | 27 | ||||
| -rw-r--r-- | executor/common_test.h | 6 | ||||
| -rw-r--r-- | executor/common_windows.h | 17 | ||||
| -rw-r--r-- | executor/executor.cc | 1 | ||||
| -rw-r--r-- | pkg/csource/common.go | 36 | ||||
| -rw-r--r-- | pkg/csource/csource.go | 208 | ||||
| -rw-r--r-- | pkg/csource/generated.go | 172 |
11 files changed, 367 insertions, 225 deletions
diff --git a/executor/common.h b/executor/common.h index 5ddfb08c5..9e6545926 100644 --- a/executor/common.h +++ b/executor/common.h @@ -2,6 +2,14 @@ // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. // This file is shared between executor and csource package. +// csource does a bunch of transformations with this file: +// - unused parts are stripped using #if SYZ* defines +// - includes are hoisted to the top and deduplicated +// - comments and empty lines are stripped +// - NORETURN/PRINTF/debug are removed +// - exitf/failf/fail are replaced with exit +// - uintN types are replaced with uintN_t +// - [[FOO]] placeholders are replaced by actual values #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -23,6 +31,11 @@ NORETURN void doexit(int status) } #endif +#if SYZ_EXECUTOR || SYZ_PROCS || SYZ_REPEAT && SYZ_ENABLE_CGROUPS || \ + __NR_syz_mount_image || __NR_syz_read_part_table +unsigned long long procid; +#endif + #if !GOOS_fuchsia && !GOOS_windows #if SYZ_EXECUTOR || SYZ_HANDLE_SEGV #include <setjmp.h> @@ -359,9 +372,6 @@ struct thread_t { static struct thread_t threads[16]; static void execute_call(int call); static int running; -#if SYZ_COLLIDE -static int collide; -#endif static void* thr(void* arg) { @@ -376,11 +386,22 @@ static void* thr(void* arg) return 0; } -static void execute(int num_calls) +#if SYZ_REPEAT +static void execute_one() +#else +static void loop() +#endif { +#if SYZ_REPRO + if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { + } +#endif int call, thread; - running = 0; - for (call = 0; call < num_calls; call++) { +#if SYZ_COLLIDE + int collide = 0; +again: +#endif + for (call = 0; call < [[NUM_CALLS]]; call++) { for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) { struct thread_t* th = &threads[thread]; if (!th->created) { @@ -402,10 +423,16 @@ static void execute(int num_calls) #endif event_timedwait(&th->done, 25); if (__atomic_load_n(&running, __ATOMIC_RELAXED)) - sleep_ms((call == num_calls - 1) ? 10 : 2); + sleep_ms((call == [[NUM_CALLS]] - 1) ? 10 : 2); break; } } +#if SYZ_COLLIDE + if (!collide) { + collide = 1; + goto again; + } +#endif } #endif @@ -428,7 +455,9 @@ static void reply_handshake(); static void loop() { +#if SYZ_HAVE_SETUP_LOOP setup_loop(); +#endif #if SYZ_EXECUTOR // Tell parent that we are ready to serve. reply_handshake(); @@ -449,7 +478,9 @@ static void loop() if (mkdir(cwdbuf, 0777)) fail("failed to mkdir"); #endif +#if SYZ_HAVE_RESET_LOOP reset_loop(); +#endif #if SYZ_EXECUTOR receive_execute(); #endif @@ -457,7 +488,9 @@ static void loop() if (pid < 0) fail("clone failed"); if (pid == 0) { +#if SYZ_HAVE_SETUP_TEST setup_test(); +#endif #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR if (chdir(cwdbuf)) fail("failed to chdir"); @@ -479,7 +512,9 @@ static void loop() #endif execute_one(); debug("worker exiting\n"); +#if SYZ_HAVE_RESET_TEST reset_test(); +#endif doexit(0); #endif } @@ -556,3 +591,61 @@ static void loop() } #endif #endif + +#if !SYZ_EXECUTOR +[[SYSCALL_DEFINES]] + +[[RESULTS]] + +#if SYZ_THREADED || SYZ_REPEAT || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE +#if SYZ_THREADED +void +execute_call(int call) +#elif SYZ_REPEAT +void +execute_one() +#else +void +loop() +#endif +{ + [[SYSCALLS]] +} +#endif + +// This is the main function for csource. +#if GOOS_akaros && SYZ_REPEAT +#include <string.h> + +int main(int argc, char** argv) +{ + [[MMAP_DATA]] + + program_name = argv[0]; + if (argc == 2 && strcmp(argv[1], "child") == 0) + child(); +#else +int +main() +{ + [[MMAP_DATA]] +#endif +#if SYZ_HANDLE_SEGV + install_segv_handler(); +#endif +#if SYZ_PROCS + for (procid = 0; procid < [[PROCS]]; procid++) { + if (fork() == 0) { +#endif +#if SYZ_USE_TMP_DIR + use_temporary_dir(); +#endif + [[SANDBOX_FUNC]] +#if SYZ_PROCS + } + } + sleep(1000000); +#endif + return 0; +} +#endif diff --git a/executor/common_akaros.h b/executor/common_akaros.h index f2f89033e..a0e42088a 100644 --- a/executor/common_akaros.h +++ b/executor/common_akaros.h @@ -3,9 +3,8 @@ // This file is shared between executor and csource package. +#include <ros/syscall.h> #include <stdlib.h> -#include <sys/mman.h> -#include <sys/syscall.h> #include <unistd.h> #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE @@ -35,9 +34,7 @@ void child() } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#endif diff --git a/executor/common_bsd.h b/executor/common_bsd.h index 164d16a36..b678dd968 100644 --- a/executor/common_bsd.h +++ b/executor/common_bsd.h @@ -14,9 +14,7 @@ static int do_sandbox_none(void) } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#endif diff --git a/executor/common_fuchsia.h b/executor/common_fuchsia.h index 1affa5650..302f49955 100644 --- a/executor/common_fuchsia.h +++ b/executor/common_fuchsia.h @@ -237,8 +237,11 @@ static int do_sandbox_none(void) } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 +#endif + #define setup_loop() #define reset_loop() #define setup_test() diff --git a/executor/common_linux.h b/executor/common_linux.h index ad653f396..4ff59aa80 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -4,7 +4,6 @@ // This file is shared between executor and csource package. #include <stdlib.h> -#include <sys/mount.h> #include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> @@ -641,8 +640,6 @@ static long syz_genetlink_get_family_id(long name) #include <sys/stat.h> #include <sys/types.h> -extern unsigned long long procid; - struct fs_image_segment { void* data; uintptr_t size; @@ -758,6 +755,9 @@ error: #endif #if SYZ_EXECUTOR || __NR_syz_mount_image +#include <string.h> +#include <sys/mount.h> + //syz_mount_image(fs ptr[in, string[disk_filesystems]], dir ptr[in, filename], size intptr, nsegs len[segments], segments ptr[in, array[fs_image_segment]], flags flags[mount_flags], opts ptr[in, fs_options[vfat_options]]) //fs_image_segment { // data ptr[in, array[int8]] @@ -885,6 +885,7 @@ static long syz_kvm_setup_cpu(long a0, long a1, long a2, long a3, long a4, long #include <fcntl.h> #include <stdarg.h> #include <stdbool.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> @@ -916,6 +917,7 @@ static bool write_file(const char* file, const char* what, ...) #include <errno.h> #include <linux/net.h> #include <netinet/in.h> +#include <string.h> #include <sys/socket.h> // checkpoint/reset_net_namespace partially resets net namespace to initial state @@ -1572,6 +1574,7 @@ static int do_sandbox_setuid(void) #include <linux/capability.h> #include <sched.h> #include <sys/mman.h> +#include <sys/mount.h> static int real_uid; static int real_gid; @@ -1706,6 +1709,8 @@ static int do_sandbox_namespace(void) #if SYZ_EXECUTOR || SYZ_REPEAT && SYZ_USE_TMP_DIR #include <dirent.h> #include <errno.h> +#include <string.h> +#include <sys/mount.h> // One does not simply remove a directory. // There can be mounts, so we need to try to umount. @@ -1795,6 +1800,7 @@ retry: #if SYZ_EXECUTOR || SYZ_FAULT_INJECTION #include <fcntl.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> @@ -1832,16 +1838,14 @@ static int fault_injected(int fail_fd) } #endif -#if SYZ_EXECUTOR || SYZ_REPEAT +#if SYZ_EXECUTOR || SYZ_REPEAT && SYZ_ENABLE_CGROUPS #include <fcntl.h> #include <sys/ioctl.h> -#include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> -extern unsigned long long procid; - +#define SYZ_HAVE_SETUP_LOOP 1 static void setup_loop() { #if SYZ_ENABLE_CGROUPS @@ -1874,7 +1878,10 @@ static void setup_loop() } #endif } +#endif +#if SYZ_EXECUTOR || SYZ_REPEAT && (SYZ_RESET_NET_NAMESPACE || __NR_syz_mount_image || __NR_syz_read_part_table) +#define SYZ_HAVE_RESET_LOOP 1 static void reset_loop() { #if SYZ_EXECUTOR || __NR_syz_mount_image || __NR_syz_read_part_table @@ -1890,7 +1897,12 @@ static void reset_loop() reset_net_namespace(); #endif } +#endif + +#if SYZ_EXECUTOR || SYZ_REPEAT +#include <sys/prctl.h> +#define SYZ_HAVE_SETUP_TEST 1 static void setup_test() { prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); @@ -1917,6 +1929,7 @@ static void setup_test() #endif } +#define SYZ_HAVE_RESET_TEST 1 static void reset_test() { // Keeping a 9p transport pipe open will hang the proccess dead, diff --git a/executor/common_test.h b/executor/common_test.h index 38accf58a..78b3f8e22 100644 --- a/executor/common_test.h +++ b/executor/common_test.h @@ -22,9 +22,7 @@ static int do_sandbox_none(void) } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#endif diff --git a/executor/common_windows.h b/executor/common_windows.h index c4fdcd66f..1aada0933 100644 --- a/executor/common_windows.h +++ b/executor/common_windows.h @@ -103,7 +103,16 @@ static int event_timedwait(event_t* ev, uint64 timeout_ms) } #endif -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE +static void loop(); +static int do_sandbox_none(void) +{ + loop(); + doexit(0); +} +#endif + +#if SYZ_EXECUTOR +#define do_sandbox_setuid() 0 +#define do_sandbox_namespace() 0 +#endif diff --git a/executor/executor.cc b/executor/executor.cc index 1efba1060..c5b9efe42 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -146,7 +146,6 @@ const uint64 binary_format_stroct = 4; const uint64 no_copyout = -1; -unsigned long long procid; int running; uint32 completed; bool collide; diff --git a/pkg/csource/common.go b/pkg/csource/common.go index 5f0cc4221..ebc085c7a 100644 --- a/pkg/csource/common.go +++ b/pkg/csource/common.go @@ -25,7 +25,7 @@ const ( sandboxNamespace = "namespace" ) -func createCommonHeader(p, mmapProg *prog.Prog, opts Options) ([]byte, error) { +func createCommonHeader(p, mmapProg *prog.Prog, replacements map[string]string, opts Options) ([]byte, error) { defines, err := defineList(p, mmapProg, opts) if err != nil { return nil, err @@ -49,6 +49,10 @@ func createCommonHeader(p, mmapProg *prog.Prog, opts Options) ([]byte, error) { return nil, err } + for from, to := range replacements { + src = bytes.Replace(src, []byte("[["+from+"]]"), []byte(to), -1) + } + for from, to := range map[string]string{ "uint64": "uint64_t", "uint32": "uint32_t", @@ -91,6 +95,9 @@ func defineList(p, mmapProg *prog.Prog, opts Options) ([]string, error) { if opts.Repeat { defines = append(defines, "SYZ_REPEAT") } + if opts.Procs > 1 { + defines = append(defines, "SYZ_PROCS") + } if opts.Fault { defines = append(defines, "SYZ_FAULT_INJECTION") } @@ -112,6 +119,9 @@ func defineList(p, mmapProg *prog.Prog, opts Options) ([]string, error) { if opts.HandleSegv { defines = append(defines, "SYZ_HANDLE_SEGV") } + if opts.Repro { + defines = append(defines, "SYZ_REPRO") + } for _, c := range p.Calls { defines = append(defines, "__NR_"+c.Meta.CallName) } @@ -131,14 +141,22 @@ func defineList(p, mmapProg *prog.Prog, opts Options) ([]string, error) { } func removeSystemDefines(src []byte, defines []string) ([]byte, error) { - remove := append(defines, []string{ - "__STDC__", - "__STDC_HOSTED__", - "__STDC_UTF_16__", - "__STDC_UTF_32__", - }...) - for _, def := range remove { - src = bytes.Replace(src, []byte("#define "+def+" 1\n"), nil, -1) + remove := map[string]string{ + "__STDC__": "1", + "__STDC_HOSTED__": "1", + "__STDC_UTF_16__": "1", + "__STDC_UTF_32__": "1", + } + for _, def := range defines { + eq := strings.IndexByte(def, '=') + if eq == -1 { + remove[def] = "1" + } else { + remove[def[:eq]] = def[eq+1:] + } + } + for def, val := range remove { + src = bytes.Replace(src, []byte("#define "+def+" "+val+"\n"), nil, -1) } // strip: #define __STDC_VERSION__ 201112L for _, def := range []string{"__STDC_VERSION__"} { diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index 512d9985a..66958f22b 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -24,7 +24,6 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { opts: opts, target: p.Target, sysTarget: targets.Get(p.Target.OS, p.Target.Arch), - w: new(bytes.Buffer), calls: make(map[string]uint64), } @@ -43,100 +42,43 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { ctx.calls[c.Meta.CallName] = c.Meta.NR } - ctx.print("// autogenerated by syzkaller (http://github.com/google/syzkaller)\n\n") - - hdr, err := createCommonHeader(p, mmapProg, opts) - if err != nil { - return nil, err - } - ctx.w.Write(hdr) - ctx.print("\n") - - ctx.generateSyscallDefines() - + varsBuf := new(bytes.Buffer) if len(vars) != 0 { - ctx.printf("uint64_t r[%v] = {", len(vars)) + fmt.Fprintf(varsBuf, "uint64 r[%v] = {", len(vars)) for i, v := range vars { if i != 0 { - ctx.printf(", ") + fmt.Fprintf(varsBuf, ", ") } - ctx.printf("0x%x", v) + fmt.Fprintf(varsBuf, "0x%x", v) } - ctx.printf("};\n") - } - needProcID := opts.Procs > 1 || opts.EnableCgroups - for _, c := range p.Calls { - if c.Meta.CallName == "syz_mount_image" || - c.Meta.CallName == "syz_read_part_table" { - needProcID = true - } - } - if needProcID { - ctx.printf("unsigned long long procid;\n") + fmt.Fprintf(varsBuf, "};\n") } - if opts.Repeat { - ctx.generateTestFunc(calls, len(vars) != 0, "execute_one") - } else { - ctx.generateTestFunc(calls, len(vars) != 0, "loop") + sandboxFunc := "loop();" + if opts.Sandbox != "" { + sandboxFunc = "do_sandbox_" + opts.Sandbox + "();" } - - if ctx.target.OS == "akaros" && opts.Repeat { - ctx.printf("const char* program_name;\n") - ctx.print("int main(int argc, char** argv)\n{\n") - } else { - ctx.print("int main()\n{\n") + replacements := map[string]string{ + "PROCS": fmt.Sprint(opts.Procs), + "NUM_CALLS": fmt.Sprint(len(p.Calls)), + "MMAP_DATA": strings.Join(mmapCalls, ""), + "SYSCALL_DEFINES": ctx.generateSyscallDefines(), + "SANDBOX_FUNC": sandboxFunc, + "RESULTS": varsBuf.String(), + "SYSCALLS": ctx.generateSyscalls(calls, len(vars) != 0), } - for _, c := range mmapCalls { - ctx.printf("%s", c) + if !opts.Threaded && !opts.Repeat && opts.Sandbox == "" { + // This inlines syscalls right into main for the simplest case. + replacements["SANDBOX_FUNC"] = replacements["SYSCALLS"] + replacements["SYSCALLS"] = "unused" } - if ctx.target.OS == "akaros" && opts.Repeat { - ctx.printf("\tprogram_name = argv[0];\n") - ctx.printf("\tif (argc == 2 && strcmp(argv[1], \"child\") == 0)\n") - ctx.printf("\t\tchild();\n") - } - if opts.HandleSegv { - ctx.printf("\tinstall_segv_handler();\n") - } - - if !opts.Repeat { - if opts.UseTmpDir { - ctx.printf("\tuse_temporary_dir();\n") - } - ctx.writeLoopCall() - } else { - if opts.UseTmpDir { - ctx.print("\tchar *cwd = get_current_dir_name();\n") - } - if opts.Procs <= 1 { - ctx.print("\tfor (;;) {\n") - if opts.UseTmpDir { - ctx.print("\t\tif (chdir(cwd))\n") - ctx.print("\t\t\tfail(\"failed to chdir\");\n") - ctx.print("\t\tuse_temporary_dir();\n") - } - ctx.writeLoopCall() - ctx.print("\t}\n") - } else { - ctx.printf("\tfor (procid = 0; procid < %v; procid++) {\n", opts.Procs) - ctx.print("\t\tif (fork() == 0) {\n") - ctx.print("\t\t\tfor (;;) {\n") - if opts.UseTmpDir { - ctx.print("\t\t\t\tif (chdir(cwd))\n") - ctx.print("\t\t\t\t\tfail(\"failed to chdir\");\n") - ctx.print("\t\t\t\tuse_temporary_dir();\n") - } - ctx.writeLoopCall() - ctx.print("\t\t\t}\n") - ctx.print("\t\t}\n") - ctx.print("\t}\n") - ctx.print("\tsleep(1000000);\n") - } + result, err := createCommonHeader(p, mmapProg, replacements, opts) + if err != nil { + return nil, err } - - ctx.print("\treturn 0;\n}\n") - - result := ctx.postProcess(ctx.w.Bytes()) + const header = "// autogenerated by syzkaller (https://github.com/google/syzkaller)\n\n" + result = append([]byte(header), result...) + result = ctx.postProcess(result) return result, nil } @@ -145,92 +87,62 @@ type context struct { 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) writeLoopCall() { - if ctx.opts.Sandbox != "" { - ctx.printf("\tdo_sandbox_%v();\n", ctx.opts.Sandbox) - return - } - if ctx.opts.EnableTun { - ctx.printf("\tinitialize_tun();\n") - } - if ctx.opts.EnableNetdev { - ctx.printf("\tinitialize_netdevices();\n") - } - ctx.print("\tloop();\n") -} - -func (ctx *context) generateTestFunc(calls []string, hasVars bool, name string) { +func (ctx *context) generateSyscalls(calls []string, hasVars bool) string { opts := ctx.opts + buf := new(bytes.Buffer) if !opts.Threaded && !opts.Collide { - ctx.printf("void %v()\n{\n", name) if hasVars { - ctx.printf("\tlong res = 0;\n") + fmt.Fprintf(buf, "\tlong res = 0;\n") } if opts.Repro { - ctx.printf("\tif (write(1, \"executing program\\n\", strlen(\"executing program\\n\"))) {}\n") + fmt.Fprintf(buf, "\tif (write(1, \"executing program\\n\", sizeof(\"executing program\\n\") - 1)) {}\n") } for _, c := range calls { - ctx.printf("%s", c) + fmt.Fprintf(buf, "%s", c) } - ctx.printf("}\n\n") } else { - ctx.printf("void execute_call(int call)\n{\n") if hasVars { - ctx.printf("\tlong res;") + fmt.Fprintf(buf, "\tlong res;") } - ctx.printf("\tswitch (call) {\n") + fmt.Fprintf(buf, "\tswitch (call) {\n") for i, c := range calls { - ctx.printf("\tcase %v:\n", i) - ctx.printf("%s", strings.Replace(c, "\t", "\t\t", -1)) - ctx.printf("\t\tbreak;\n") - } - ctx.printf("\t}\n") - ctx.printf("}\n\n") - - ctx.printf("void %v()\n{\n", name) - if opts.Repro { - ctx.printf("\tif (write(1, \"executing program\\n\", strlen(\"executing program\\n\"))) {}\n") - } - ctx.printf("\texecute(%v);\n", len(calls)) - if opts.Collide { - ctx.printf("\tcollide = 1;\n") - ctx.printf("\texecute(%v);\n", len(calls)) + fmt.Fprintf(buf, "\tcase %v:\n", i) + fmt.Fprintf(buf, "%s", strings.Replace(c, "\t", "\t\t", -1)) + fmt.Fprintf(buf, "\t\tbreak;\n") } - ctx.printf("}\n\n") + fmt.Fprintf(buf, "\t}\n") } + return buf.String() } -func (ctx *context) generateSyscallDefines() { - prefix := ctx.sysTarget.SyscallPrefix +func (ctx *context) generateSyscallDefines() string { + var calls []string for name, nr := range ctx.calls { if !ctx.sysTarget.SyscallNumbers || strings.HasPrefix(name, "syz_") || !ctx.sysTarget.NeedSyscallDefine(nr) { continue } - ctx.printf("#ifndef %v%v\n", prefix, name) - ctx.printf("#define %v%v %v\n", prefix, name, nr) - ctx.printf("#endif\n") + calls = append(calls, name) + } + sort.Strings(calls) + buf := new(bytes.Buffer) + prefix := ctx.sysTarget.SyscallPrefix + for _, name := range calls { + fmt.Fprintf(buf, "#ifndef %v%v\n", prefix, name) + fmt.Fprintf(buf, "#define %v%v %v\n", prefix, name, ctx.calls[name]) + fmt.Fprintf(buf, "#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. syz-extract translates mmap to mmap2, do the same here. - ctx.printf("#undef __NR_mmap\n") - ctx.printf("#define __NR_mmap __NR_mmap2\n") + fmt.Fprintf(buf, "#undef __NR_mmap\n") + fmt.Fprintf(buf, "#define __NR_mmap __NR_mmap2\n") } - ctx.printf("\n") + return buf.String() } func (ctx *context) generateProgCalls(p *prog.Prog) ([]string, []uint64, error) { @@ -332,7 +244,7 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, []uint64) { fmt.Fprintf(w, "\t\tr[%v] = res;\n", call.Index) } for _, copyout := range call.Copyout { - fmt.Fprintf(w, "\t\tNONFAILING(r[%v] = *(uint%v_t*)0x%x);\n", + fmt.Fprintf(w, "\t\tNONFAILING(r[%v] = *(uint%v*)0x%x);\n", copyout.Index, copyout.Size*8, copyout.Addr) } if copyoutMultiple { @@ -350,18 +262,18 @@ func (ctx *context) generateCsumInet(w *bytes.Buffer, addr uint64, arg prog.Exec for i, chunk := range arg.Chunks { switch chunk.Kind { case prog.ExecArgCsumChunkData: - fmt.Fprintf(w, "\tNONFAILING(csum_inet_update(&csum_%d, (const uint8_t*)0x%x, %d));\n", + fmt.Fprintf(w, "\tNONFAILING(csum_inet_update(&csum_%d, (const uint8*)0x%x, %d));\n", csumSeq, chunk.Value, chunk.Size) case prog.ExecArgCsumChunkConst: - fmt.Fprintf(w, "\tuint%d_t csum_%d_chunk_%d = 0x%x;\n", + fmt.Fprintf(w, "\tuint%d csum_%d_chunk_%d = 0x%x;\n", chunk.Size*8, csumSeq, i, chunk.Value) - fmt.Fprintf(w, "\tcsum_inet_update(&csum_%d, (const uint8_t*)&csum_%d_chunk_%d, %d);\n", + fmt.Fprintf(w, "\tcsum_inet_update(&csum_%d, (const uint8*)&csum_%d_chunk_%d, %d);\n", csumSeq, csumSeq, i, chunk.Size) default: panic(fmt.Sprintf("unknown checksum chunk kind %v", chunk.Kind)) } } - fmt.Fprintf(w, "\tNONFAILING(*(uint16_t*)0x%x = csum_inet_digest(&csum_%d));\n", + fmt.Fprintf(w, "\tNONFAILING(*(uint16*)0x%x = csum_inet_digest(&csum_%d));\n", addr, csumSeq) } @@ -374,7 +286,7 @@ func (ctx *context) copyin(w *bytes.Buffer, csumSeq *int, copyin prog.ExecCopyin if arg.Format != prog.FormatNative && arg.Format != prog.FormatBigEndian { panic("bitfield+string format") } - fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v_t, 0x%x, %v, %v, %v));\n", + fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v, 0x%x, %v, %v, %v));\n", arg.Size*8, copyin.Addr, ctx.constArgToStr(arg), arg.BitfieldOffset, arg.BitfieldLength) } @@ -399,7 +311,7 @@ func (ctx *context) copyin(w *bytes.Buffer, csumSeq *int, copyin prog.ExecCopyin func (ctx *context) copyinVal(w *bytes.Buffer, addr, size uint64, val string, bf prog.BinaryFormat) { switch bf { case prog.FormatNative, prog.FormatBigEndian: - fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n", size*8, addr, val) + fmt.Fprintf(w, "\tNONFAILING(*(uint%v*)0x%x = %v);\n", size*8, addr, val) case prog.FormatStrDec: if size != 20 { panic("bad strdec size") @@ -506,6 +418,8 @@ func (ctx *context) hoistIncludes(result []byte) []byte { func (ctx *context) removeEmptyLines(result []byte) []byte { for { newResult := bytes.Replace(result, []byte{'\n', '\n', '\n'}, []byte{'\n', '\n'}, -1) + newResult = bytes.Replace(newResult, []byte{'\n', '\n', '\t'}, []byte{'\n', '\t'}, -1) + newResult = bytes.Replace(newResult, []byte{'\n', '\n', ' '}, []byte{'\n', ' '}, -1) if len(newResult) == len(result) { return result } diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go index 9c9241010..7cd6f8777 100644 --- a/pkg/csource/generated.go +++ b/pkg/csource/generated.go @@ -25,6 +25,11 @@ NORETURN void doexit(int status) } #endif +#if SYZ_EXECUTOR || SYZ_PROCS || SYZ_REPEAT && SYZ_ENABLE_CGROUPS || \ + __NR_syz_mount_image || __NR_syz_read_part_table +unsigned long long procid; +#endif + #if !GOOS_fuchsia && !GOOS_windows #if SYZ_EXECUTOR || SYZ_HANDLE_SEGV #include <setjmp.h> @@ -328,9 +333,8 @@ static uint16 csum_inet_digest(struct csum_inet* csum) #if GOOS_akaros +#include <ros/syscall.h> #include <stdlib.h> -#include <sys/mman.h> -#include <sys/syscall.h> #include <unistd.h> #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE @@ -360,12 +364,10 @@ void child() } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#endif #elif GOOS_freebsd || GOOS_netbsd @@ -380,12 +382,10 @@ static int do_sandbox_none(void) } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#endif #elif GOOS_fuchsia @@ -622,8 +622,11 @@ static int do_sandbox_none(void) } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 +#endif + #define setup_loop() #define reset_loop() #define setup_test() @@ -632,7 +635,6 @@ static int do_sandbox_none(void) #include <stdlib.h> -#include <sys/mount.h> #include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> @@ -1221,8 +1223,6 @@ static long syz_genetlink_get_family_id(long name) #include <sys/stat.h> #include <sys/types.h> -extern unsigned long long procid; - struct fs_image_segment { void* data; uintptr_t size; @@ -1335,6 +1335,9 @@ error: #endif #if SYZ_EXECUTOR || __NR_syz_mount_image +#include <string.h> +#include <sys/mount.h> + static long syz_mount_image(long fsarg, long dir, unsigned long size, unsigned long nsegs, long segments, long flags, long optsarg) { char loopname[64], fs[32], opts[256]; @@ -2399,6 +2402,7 @@ static long syz_kvm_setup_cpu(long a0, long a1, long a2, long a3, long a4, long #include <fcntl.h> #include <stdarg.h> #include <stdbool.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> @@ -2430,6 +2434,7 @@ static bool write_file(const char* file, const char* what, ...) #include <errno.h> #include <linux/net.h> #include <netinet/in.h> +#include <string.h> #include <sys/socket.h> @@ -3067,6 +3072,7 @@ static int do_sandbox_setuid(void) #include <linux/capability.h> #include <sched.h> #include <sys/mman.h> +#include <sys/mount.h> static int real_uid; static int real_gid; @@ -3189,6 +3195,8 @@ static int do_sandbox_namespace(void) #if SYZ_EXECUTOR || SYZ_REPEAT && SYZ_USE_TMP_DIR #include <dirent.h> #include <errno.h> +#include <string.h> +#include <sys/mount.h> static void remove_dir(const char* dir) { @@ -3268,6 +3276,7 @@ retry: #if SYZ_EXECUTOR || SYZ_FAULT_INJECTION #include <fcntl.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> @@ -3302,16 +3311,14 @@ static int fault_injected(int fail_fd) } #endif -#if SYZ_EXECUTOR || SYZ_REPEAT +#if SYZ_EXECUTOR || SYZ_REPEAT && SYZ_ENABLE_CGROUPS #include <fcntl.h> #include <sys/ioctl.h> -#include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> -extern unsigned long long procid; - +#define SYZ_HAVE_SETUP_LOOP 1 static void setup_loop() { #if SYZ_ENABLE_CGROUPS @@ -3344,7 +3351,10 @@ static void setup_loop() } #endif } +#endif +#if SYZ_EXECUTOR || SYZ_REPEAT && (SYZ_RESET_NET_NAMESPACE || __NR_syz_mount_image || __NR_syz_read_part_table) +#define SYZ_HAVE_RESET_LOOP 1 static void reset_loop() { #if SYZ_EXECUTOR || __NR_syz_mount_image || __NR_syz_read_part_table @@ -3360,7 +3370,12 @@ static void reset_loop() reset_net_namespace(); #endif } +#endif +#if SYZ_EXECUTOR || SYZ_REPEAT +#include <sys/prctl.h> + +#define SYZ_HAVE_SETUP_TEST 1 static void setup_test() { prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); @@ -3385,6 +3400,7 @@ static void setup_test() #endif } +#define SYZ_HAVE_RESET_TEST 1 static void reset_test() { int fd; @@ -3414,12 +3430,10 @@ static int do_sandbox_none(void) } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#endif #elif GOOS_windows @@ -3523,10 +3537,19 @@ static int event_timedwait(event_t* ev, uint64 timeout_ms) } #endif -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE +static void loop(); +static int do_sandbox_none(void) +{ + loop(); + doexit(0); +} +#endif + +#if SYZ_EXECUTOR +#define do_sandbox_setuid() 0 +#define do_sandbox_namespace() 0 +#endif #elif GOOS_test @@ -3549,12 +3572,10 @@ static int do_sandbox_none(void) } #endif +#if SYZ_EXECUTOR #define do_sandbox_setuid() 0 #define do_sandbox_namespace() 0 -#define setup_loop() -#define reset_loop() -#define setup_test() -#define reset_test() +#endif #else #error "unknown OS" #endif @@ -3568,9 +3589,6 @@ struct thread_t { static struct thread_t threads[16]; static void execute_call(int call); static int running; -#if SYZ_COLLIDE -static int collide; -#endif static void* thr(void* arg) { @@ -3585,11 +3603,22 @@ static void* thr(void* arg) return 0; } -static void execute(int num_calls) +#if SYZ_REPEAT +static void execute_one() +#else +static void loop() +#endif { +#if SYZ_REPRO + if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { + } +#endif int call, thread; - running = 0; - for (call = 0; call < num_calls; call++) { +#if SYZ_COLLIDE + int collide = 0; +again: +#endif + for (call = 0; call < [[NUM_CALLS]]; call++) { for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) { struct thread_t* th = &threads[thread]; if (!th->created) { @@ -3611,10 +3640,16 @@ static void execute(int num_calls) #endif event_timedwait(&th->done, 25); if (__atomic_load_n(&running, __ATOMIC_RELAXED)) - sleep_ms((call == num_calls - 1) ? 10 : 2); + sleep_ms((call == [[NUM_CALLS]] - 1) ? 10 : 2); break; } } +#if SYZ_COLLIDE + if (!collide) { + collide = 1; + goto again; + } +#endif } #endif @@ -3637,7 +3672,9 @@ static void reply_handshake(); static void loop() { +#if SYZ_HAVE_SETUP_LOOP setup_loop(); +#endif #if SYZ_EXECUTOR reply_handshake(); #endif @@ -3654,7 +3691,9 @@ static void loop() if (mkdir(cwdbuf, 0777)) fail("failed to mkdir"); #endif +#if SYZ_HAVE_RESET_LOOP reset_loop(); +#endif #if SYZ_EXECUTOR receive_execute(); #endif @@ -3662,7 +3701,9 @@ static void loop() if (pid < 0) fail("clone failed"); if (pid == 0) { +#if SYZ_HAVE_SETUP_TEST setup_test(); +#endif #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR if (chdir(cwdbuf)) fail("failed to chdir"); @@ -3684,7 +3725,9 @@ static void loop() #endif execute_one(); debug("worker exiting\n"); +#if SYZ_HAVE_RESET_TEST reset_test(); +#endif doexit(0); #endif } @@ -3746,4 +3789,61 @@ static void loop() } #endif #endif + +#if !SYZ_EXECUTOR +[[SYSCALL_DEFINES]] + +[[RESULTS]] + +#if SYZ_THREADED || SYZ_REPEAT || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE +#if SYZ_THREADED +void +execute_call(int call) +#elif SYZ_REPEAT +void +execute_one() +#else +void +loop() +#endif +{ + [[SYSCALLS]] +} +#endif + +#if GOOS_akaros && SYZ_REPEAT +#include <string.h> + +int main(int argc, char** argv) +{ + [[MMAP_DATA]] + + program_name = argv[0]; + if (argc == 2 && strcmp(argv[1], "child") == 0) + child(); +#else +int +main() +{ + [[MMAP_DATA]] +#endif +#if SYZ_HANDLE_SEGV + install_segv_handler(); +#endif +#if SYZ_PROCS + for (procid = 0; procid < [[PROCS]]; procid++) { + if (fork() == 0) { +#endif +#if SYZ_USE_TMP_DIR + use_temporary_dir(); +#endif + [[SANDBOX_FUNC]] +#if SYZ_PROCS + } + } + sleep(1000000); +#endif + return 0; +} +#endif ` |
