diff options
Diffstat (limited to 'pkg/csource')
| -rw-r--r-- | pkg/csource/common.go | 3 | ||||
| -rw-r--r-- | pkg/csource/csource.go | 6 | ||||
| -rw-r--r-- | pkg/csource/generated.go | 189 | ||||
| -rw-r--r-- | pkg/csource/options.go | 5 |
4 files changed, 165 insertions, 38 deletions
diff --git a/pkg/csource/common.go b/pkg/csource/common.go index d0c63402a..587c0f587 100644 --- a/pkg/csource/common.go +++ b/pkg/csource/common.go @@ -8,6 +8,7 @@ package csource import ( "bytes" "fmt" + "regexp" "runtime" "sort" "strings" @@ -61,6 +62,7 @@ func createCommonHeader(p, mmapProg *prog.Prog, replacements map[string]string, } { src = bytes.Replace(src, []byte(from), []byte(to), -1) } + src = regexp.MustCompile("#define SYZ_HAVE_.*").ReplaceAll(src, nil) return src, nil } @@ -84,6 +86,7 @@ func defineList(p, mmapProg *prog.Prog, opts Options) (defines []string) { "SYZ_REPEAT_TIMES": opts.RepeatTimes > 1, "SYZ_PROCS": opts.Procs > 1, "SYZ_FAULT_INJECTION": opts.Fault, + "SYZ_ENABLE_LEAK": opts.Leak, "SYZ_TUN_ENABLE": opts.EnableTun, "SYZ_ENABLE_CGROUPS": opts.EnableCgroups, "SYZ_ENABLE_NETDEV": opts.EnableNetDev, diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index c5beb68c6..c8513286f 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -174,12 +174,6 @@ func (ctx *context) generateCalls(p prog.ExecProg, trace bool) ([]string, []uint } if ctx.opts.Fault && ctx.opts.FaultCall == ci { - // Note: these files are also hardcoded in pkg/host/host_linux.go. - fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/failslab/ignore-gfp-wait\", \"N\");\n") - fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_futex/ignore-private\", \"N\");\n") - fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem\", \"N\");\n") - fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait\", \"N\");\n") - fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_page_alloc/min-order\", \"0\");\n") fmt.Fprintf(w, "\tinject_fault(%v);\n", ctx.opts.FaultNth) } // Call itself. diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go index 7f1424f36..53458f2f6 100644 --- a/pkg/csource/generated.go +++ b/pkg/csource/generated.go @@ -130,7 +130,8 @@ static void sleep_ms(uint64 ms) } #endif -#if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER +#if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER || \ + SYZ_ENABLE_LEAK #include <time.h> static uint64 current_time_ms(void) @@ -203,7 +204,7 @@ static void remove_dir(const char* dir) #endif #if !GOOS_linux -#if SYZ_EXECUTOR || SYZ_FAULT_INJECTION +#if SYZ_EXECUTOR static int inject_fault(int nth) { return 0; @@ -1072,7 +1073,8 @@ static int event_timedwait(event_t* ev, uint64 timeout) #endif #if SYZ_EXECUTOR || SYZ_REPEAT || SYZ_TUN_ENABLE || SYZ_FAULT_INJECTION || SYZ_SANDBOX_NONE || \ - SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID_UNTRUSTED_APP + SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID_UNTRUSTED_APP || \ + SYZ_FAULT_INJECTION || SYZ_ENABLE_LEAK || SYZ_ENABLE_BINFMT_MISC #include <errno.h> #include <fcntl.h> #include <stdarg.h> @@ -4156,26 +4158,6 @@ void initialize_cgroups() #endif #endif -#if SYZ_EXECUTOR || (SYZ_ENABLE_BINFMT_MISC && (SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID_UNTRUSTED_APP)) -#include <fcntl.h> -#include <sys/mount.h> -#include <sys/stat.h> -#include <sys/types.h> - -static void setup_binfmt_misc() -{ -#if SYZ_EXECUTOR - if (!flag_enable_binfmt_misc) - return; -#endif - if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) { - debug("mount(binfmt_misc) failed: %d\n", errno); - } - write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:"); - write_file("/proc/sys/fs/binfmt_misc/register", ":syz1:M:1:\x02::./file0:POC"); -} -#endif - #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID_UNTRUSTED_APP #include <errno.h> #include <sys/mount.h> @@ -4188,9 +4170,6 @@ static void setup_common() #if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS setup_cgroups(); #endif -#if SYZ_EXECUTOR || SYZ_ENABLE_BINFMT_MISC - setup_binfmt_misc(); -#endif } #include <sched.h> @@ -4687,10 +4666,6 @@ retry: static int inject_fault(int nth) { -#if SYZ_EXECUTOR - if (!flag_enable_fault_injection) - return 0; -#endif int fd; fd = open("/proc/thread-self/fail-nth", O_RDWR); if (fd == -1) @@ -4706,8 +4681,6 @@ static int inject_fault(int nth) #if SYZ_EXECUTOR static int fault_injected(int fail_fd) { - if (!flag_enable_fault_injection) - return 0; char buf[16]; int n = read(fail_fd, buf, sizeof(buf) - 1); if (n <= 0) @@ -4842,6 +4815,142 @@ static void close_fds() } #endif +#if SYZ_EXECUTOR || SYZ_FAULT_INJECTION +#include <errno.h> + +static void setup_fault() +{ + static struct { + const char* file; + const char* val; + bool fatal; + } files[] = { + {"/sys/kernel/debug/failslab/ignore-gfp-wait", "N", true}, + {"/sys/kernel/debug/fail_futex/ignore-private", "N", false}, + {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem", "N", false}, + {"/sys/kernel/debug/fail_page_alloc/ignore-gfp-wait", "N", false}, + {"/sys/kernel/debug/fail_page_alloc/min-order", "0", false}, + }; + unsigned i; + for (i = 0; i < sizeof(files) / sizeof(files[0]); i++) { + if (!write_file(files[i].file, files[i].val)) { + debug("failed to write %s: %d\n", files[i].file, errno); + if (files[i].fatal) + fail("failed to write %s", files[i].file); + } + } +} +#endif + +#if SYZ_EXECUTOR || SYZ_ENABLE_LEAK +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> + +#define KMEMLEAK_FILE "/sys/kernel/debug/kmemleak" + +static void setup_leak() +{ + if (!write_file(KMEMLEAK_FILE, "scan")) + fail("failed to write %s", KMEMLEAK_FILE); + sleep(5); + if (!write_file(KMEMLEAK_FILE, "scan")) + fail("failed to write %s", KMEMLEAK_FILE); + if (!write_file(KMEMLEAK_FILE, "clear")) + fail("failed to write %s", KMEMLEAK_FILE); +} + +#define SYZ_HAVE_LEAK_CHECK 1 +#if SYZ_EXECUTOR +static void check_leaks(char** frames, int nframes) +#else +static void check_leaks(void) +#endif +{ + int fd = open(KMEMLEAK_FILE, O_RDWR); + if (fd == -1) + fail("failed to open(\"%s\")", KMEMLEAK_FILE); + uint64 start = current_time_ms(); + if (write(fd, "scan", 4) != 4) + fail("failed to write(%s, \"scan\")", KMEMLEAK_FILE); + sleep(1); + while (current_time_ms() - start < 4 * 1000) + sleep(1); + if (write(fd, "scan", 4) != 4) + fail("failed to write(%s, \"scan\")", KMEMLEAK_FILE); + static char buf[128 << 10]; + ssize_t n = read(fd, buf, sizeof(buf) - 1); + if (n < 0) + fail("failed to read(%s)", KMEMLEAK_FILE); +#if SYZ_EXECUTOR + int nleaks = 0; +#endif + if (n != 0) { + sleep(1); + if (write(fd, "scan", 4) != 4) + fail("failed to write(%s, \"scan\")", KMEMLEAK_FILE); + if (lseek(fd, 0, SEEK_SET) < 0) + fail("failed to lseek(%s)", KMEMLEAK_FILE); + n = read(fd, buf, sizeof(buf) - 1); + if (n < 0) + fail("failed to read(%s)", KMEMLEAK_FILE); + buf[n] = 0; + char* pos = buf; + char* end = buf + n; + while (pos < end) { + char* next = strstr(pos + 1, "unreferenced object"); + if (!next) + next = end; + char prev = *next; + *next = 0; +#if SYZ_EXECUTOR + int f; + for (f = 0; f < nframes; f++) { + if (strstr(pos, frames[f])) + break; + } + if (f != nframes) { + *next = prev; + pos = next; + continue; + } +#endif + fprintf(stderr, "BUG: memory leak\n%s\n", pos); + *next = prev; + pos = next; +#if SYZ_EXECUTOR + nleaks++; +#endif + } + } + if (write(fd, "clear", 5) != 5) + fail("failed to write(%s, \"clear\")", KMEMLEAK_FILE); + close(fd); +#if SYZ_EXECUTOR + if (nleaks) + doexit(1); +#endif +} +#endif + +#if SYZ_EXECUTOR || SYZ_ENABLE_BINFMT_MISC +#include <fcntl.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <sys/types.h> + +static void setup_binfmt_misc() +{ + if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) { + debug("mount(binfmt_misc) failed: %d\n", errno); + } + write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\x01::./file0:"); + write_file("/proc/sys/fs/binfmt_misc/register", ":syz1:M:1:\x02::./file0:POC"); +} +#endif + #elif GOOS_test #include <stdlib.h> @@ -5262,6 +5371,9 @@ static void loop(void) #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR remove_dir(cwdbuf); #endif +#if SYZ_ENABLE_LEAK + check_leaks(); +#endif } } #else @@ -5308,6 +5420,16 @@ int main(void) /*MMAP_DATA*/ #endif +#if SYZ_ENABLE_BINFMT_MISC + setup_binfmt_misc(); +#endif +#if SYZ_ENABLE_LEAK + setup_leak(); +#endif +#if SYZ_FAULT_INJECTION + setup_fault(); +#endif + #if SYZ_HANDLE_SEGV install_segv_handler(); #endif @@ -5328,6 +5450,9 @@ int main(void) } sleep(1000000); #endif +#if !SYZ_PROCS && !SYZ_REPEAT && SYZ_ENABLE_LEAK + check_leaks(); +#endif return 0; } #endif diff --git a/pkg/csource/options.go b/pkg/csource/options.go index 61094456f..e63a76890 100644 --- a/pkg/csource/options.go +++ b/pkg/csource/options.go @@ -28,6 +28,8 @@ type Options struct { FaultCall int `json:"fault_call,omitempty"` FaultNth int `json:"fault_nth,omitempty"` + Leak bool `json:"leak,omitempty"` // do leak checking + // These options allow for a more fine-tuned control over the generated C code. EnableTun bool `json:"tun,omitempty"` EnableNetDev bool `json:"netdev,omitempty"` @@ -129,6 +131,9 @@ func (opts Options) checkLinuxOnly(OS string) error { if opts.Fault { return fmt.Errorf("option Fault is not supported on %v", OS) } + if opts.Leak { + return fmt.Errorf("option Leak is not supported on %v", OS) + } return nil } |
