diff options
| -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 ` |
