aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/csource
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/csource')
-rw-r--r--pkg/csource/common.go3
-rw-r--r--pkg/csource/csource.go6
-rw-r--r--pkg/csource/generated.go189
-rw-r--r--pkg/csource/options.go5
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
}