aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/csource/generated.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-05-18 17:54:03 +0200
committerDmitry Vyukov <dvyukov@google.com>2019-05-20 19:40:20 +0200
commit8285069f89c9942f65ce760a8f0a5a12254bfeeb (patch)
treedf5cc7298195f227005e11489fdad8c25458847e /pkg/csource/generated.go
parent7b3084af2ea815515ea35f9904ee38b5991e58d5 (diff)
executor: implement support for leak checking
Leak checking support was half done and did not really work. This is heavy-lifting to make it work. 1. Move leak/fault setup into executor. pkg/host was a wrong place for them because we need then in C repros too. The pkg/host periodic callback functionality did not work too, we need it in executor so that we can reuse it in C repros too. Remove setup/callback functions in pkg/host entirely. 2. Do leak setup/checking in C repros. The way leak checking is invoked is slightly different from fuzzer, but much better then no support at all. At least the checking code is shared. 3. Add Leak option to pkg/csource and -leak flag to syz-prog2c. 4. Don't enalbe leak checking in fuzzer while we are triaging initial corpus. It's toooo slow. 5. Fix pkg/repro to do something more sane for leak bugs. Few other minor fixes here and there.
Diffstat (limited to 'pkg/csource/generated.go')
-rw-r--r--pkg/csource/generated.go189
1 files changed, 157 insertions, 32 deletions
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