aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@google.com>2019-02-05 16:19:34 +0100
committerAndrey Konovalov <andreyknvl@gmail.com>2019-03-05 14:30:10 +0100
commitdfd609eca1871f01757d6b04b19fc273c87c14e5 (patch)
treebd16e4561775f52e40f970a35a032f1f390171a9
parentc55829aef16e95df564cb23e700e5de8490229a0 (diff)
execprog, stress, prog2c: unify flags to enable additional features
This change makes all syz-execprog, syz-prog2c and syz-stress accept -enable and -disable flags to enable or disable additional features (tun, net_dev, net_reset, cgroups and binfmt_misc) instead of having a separate flag for each of them. The default (without any flags) behavior isn't changed: syz-execprog and syz-stress enabled all the features (provided the runtime supports them) and syz-prog2c disables all of them.
-rw-r--r--docs/syzbot.md2
-rw-r--r--executor/common.h1
-rw-r--r--executor/common_linux.h218
-rw-r--r--executor/executor.cc18
-rw-r--r--pkg/csource/common.go5
-rw-r--r--pkg/csource/generated.go188
-rw-r--r--pkg/csource/options.go141
-rw-r--r--pkg/csource/options_test.go189
-rw-r--r--pkg/ipc/ipc.go9
-rw-r--r--pkg/repro/repro.go26
-rw-r--r--pkg/repro/repro_test.go24
-rw-r--r--pkg/runtest/run.go4
-rw-r--r--syz-fuzzer/fuzzer.go9
-rw-r--r--tools/syz-execprog/execprog.go37
-rw-r--r--tools/syz-prog2c/prog2c.go54
-rw-r--r--tools/syz-stress/stress.go28
16 files changed, 633 insertions, 320 deletions
diff --git a/docs/syzbot.md b/docs/syzbot.md
index 94fdb62b0..db5e0110d 100644
--- a/docs/syzbot.md
+++ b/docs/syzbot.md
@@ -98,7 +98,7 @@ parallel).
A syzkaller program can be converted to an almost equivalent C source using `syz-prog2c` utility. `syz-prog2c` has lots of flags in common with [syz-execprog](https://github.com/google/syzkaller/blob/master/docs/executing_syzkaller_programs.md), e.g. `-threaded`/`-collide` which control if the syscalls are executed sequentially or in parallel. An example invocation:
```
-syz-prog2c -prog repro.syz.txt -threaded -collide -repeat -procs=8 -sandbox=namespace -tun -tmpdir -waitrepeat
+syz-prog2c -prog repro.syz.txt -enable=all -threaded -collide -repeat -procs=8 -sandbox=namespace -segv -tmpdir -waitrepeat
```
However, note that if `syzbot` did not provide a C reproducer, it wasn't able to trigger the bug using the C program (though, it can be just because the bug is triggered by a subtle race condition).
diff --git a/executor/common.h b/executor/common.h
index 89dfbd58c..1f8e4b441 100644
--- a/executor/common.h
+++ b/executor/common.h
@@ -223,6 +223,7 @@ static int inject_fault(int nth)
return 0;
}
#endif
+
#if SYZ_EXECUTOR
static int fault_injected(int fail_fd)
{
diff --git a/executor/common_linux.h b/executor/common_linux.h
index 26137e5b7..0e185553c 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -70,7 +70,7 @@ static int event_timedwait(event_t* ev, uint64 timeout)
}
#endif
-#if SYZ_EXECUTOR || SYZ_FAULT_INJECTION || SYZ_ENABLE_CGROUPS || SYZ_SANDBOX_NONE || \
+#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
#include <errno.h>
#include <fcntl.h>
@@ -1677,6 +1677,8 @@ static void reset_ebtables()
static void checkpoint_net_namespace(void)
{
#if SYZ_EXECUTOR
+ if (!flag_enable_net_reset)
+ return;
if (flag_sandbox == sandbox_setuid)
return;
#endif
@@ -1689,6 +1691,8 @@ static void checkpoint_net_namespace(void)
static void reset_net_namespace(void)
{
#if SYZ_EXECUTOR
+ if (!flag_enable_net_reset)
+ return;
if (flag_sandbox == sandbox_setuid)
return;
#endif
@@ -1699,7 +1703,7 @@ static void reset_net_namespace(void)
}
#endif
-#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
+#if SYZ_EXECUTOR || (SYZ_ENABLE_CGROUPS && (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>
@@ -1707,6 +1711,10 @@ static void reset_net_namespace(void)
static void setup_cgroups()
{
+#if SYZ_EXECUTOR
+ if (!flag_enable_cgroups)
+ return;
+#endif
if (mkdir("/syzcgroup", 0777)) {
debug("mkdir(/syzcgroup) failed: %d\n", errno);
}
@@ -1741,10 +1749,122 @@ static void setup_cgroups()
}
}
-// TODO(dvyukov): this should be under a separate define for separate minimization,
-// but for now we bundle this with cgroups.
+#if SYZ_EXECUTOR || SYZ_REPEAT
+static void setup_cgroups_loop()
+{
+#if SYZ_EXECUTOR
+ if (!flag_enable_cgroups)
+ return;
+#endif
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
+ }
+ // Restrict number of pids per test process to prevent fork bombs.
+ // We have up to 16 threads + main process + loop.
+ // 32 pids should be enough for everyone.
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ // Restrict memory consumption.
+ // We have some syscalls that inherently consume lots of memory,
+ // e.g. mounting some filesystem images requires at least 128MB
+ // image in memory. We restrict RLIMIT_AS to 200MB. Here we gradually
+ // increase low/high/max limits to make things more interesting.
+ // Also this takes into account KASAN quarantine size.
+ // If the limit is lower than KASAN quarantine size, then it can happen
+ // so that we kill the process, but all of its memory is in quarantine
+ // and is still accounted against memcg. As the result memcg won't
+ // allow to allocate any memory in the parent and in the new test process.
+ // The current limit of 300MB supports up to 9.6GB RAM (quarantine is 1/32).
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ // Setup some v1 groups to make things more interesting.
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+#if SYZ_EXECUTOR
+ if (!flag_enable_cgroups)
+ return;
+#endif
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ debug("symlink(%s, ./cgroup) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ debug("symlink(%s, ./cgroup.cpu) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ debug("symlink(%s, ./cgroup.net) failed: %d\n", cgroupdir, errno);
+ }
+}
+#endif
+
+#if SYZ_EXECUTOR || SYZ_SANDBOX_NAMESPACE
+void initialize_cgroups()
+{
+#if SYZ_EXECUTOR
+ if (!flag_enable_cgroups)
+ return;
+#endif
+ if (mkdir("./syz-tmp/newroot/syzcgroup", 0700))
+ fail("mkdir failed");
+ if (mkdir("./syz-tmp/newroot/syzcgroup/unified", 0700))
+ fail("mkdir failed");
+ if (mkdir("./syz-tmp/newroot/syzcgroup/cpu", 0700))
+ fail("mkdir failed");
+ if (mkdir("./syz-tmp/newroot/syzcgroup/net", 0700))
+ fail("mkdir failed");
+ unsigned bind_mount_flags = MS_BIND | MS_REC | MS_PRIVATE;
+ if (mount("/syzcgroup/unified", "./syz-tmp/newroot/syzcgroup/unified", NULL, bind_mount_flags, NULL)) {
+ debug("mount(cgroup2, MS_BIND) failed: %d\n", errno);
+ }
+ if (mount("/syzcgroup/cpu", "./syz-tmp/newroot/syzcgroup/cpu", NULL, bind_mount_flags, NULL)) {
+ debug("mount(cgroup/cpu, MS_BIND) failed: %d\n", errno);
+ }
+ if (mount("/syzcgroup/net", "./syz-tmp/newroot/syzcgroup/net", NULL, bind_mount_flags, NULL)) {
+ debug("mount(cgroup/net, MS_BIND) failed: %d\n", errno);
+ }
+}
+#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);
}
@@ -1764,6 +1884,8 @@ static void setup_common()
}
#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
setup_cgroups();
+#endif
+#if SYZ_EXECUTOR || SYZ_ENABLE_BINFMT_MISC
setup_binfmt_misc();
#endif
}
@@ -2017,23 +2139,7 @@ static int namespace_sandbox_proc(void* arg)
if (mount("/sys", "./syz-tmp/newroot/sys", 0, bind_mount_flags, NULL))
fail("mount(sysfs) failed");
#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
- if (mkdir("./syz-tmp/newroot/syzcgroup", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/unified", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/cpu", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/net", 0700))
- fail("mkdir failed");
- if (mount("/syzcgroup/unified", "./syz-tmp/newroot/syzcgroup/unified", NULL, bind_mount_flags, NULL)) {
- debug("mount(cgroup2, MS_BIND) failed: %d\n", errno);
- }
- if (mount("/syzcgroup/cpu", "./syz-tmp/newroot/syzcgroup/cpu", NULL, bind_mount_flags, NULL)) {
- debug("mount(cgroup/cpu, MS_BIND) failed: %d\n", errno);
- }
- if (mount("/syzcgroup/net", "./syz-tmp/newroot/syzcgroup/net", NULL, bind_mount_flags, NULL)) {
- debug("mount(cgroup/net, MS_BIND) failed: %d\n", errno);
- }
+ initialize_cgroups();
#endif
if (mkdir("./syz-tmp/pivot", 0777))
fail("mkdir failed");
@@ -2354,15 +2460,18 @@ retry:
static int inject_fault(int nth)
{
+#if SYZ_EXECUTOR
+ if (!flag_enable_fault_injection)
+ return 0;
+#endif
int fd;
- char buf[16];
-
fd = open("/proc/thread-self/fail-nth", O_RDWR);
// We treat errors here as temporal/non-critical because we see
// occasional ENOENT/EACCES errors returned. It seems that fuzzer
// somehow gets its hands to it.
if (fd == -1)
exitf("failed to open /proc/thread-self/fail-nth");
+ char buf[16];
sprintf(buf, "%d", nth + 1);
if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
exitf("failed to write /proc/thread-self/fail-nth");
@@ -2373,6 +2482,8 @@ 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)
@@ -2455,50 +2566,7 @@ static void kill_and_wait(int pid, int* status)
static void setup_loop()
{
#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
- int pid = getpid();
- char cgroupdir[64];
- char file[128];
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
- if (mkdir(cgroupdir, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
- }
- // Restrict number of pids per test process to prevent fork bombs.
- // We have up to 16 threads + main process + loop.
- // 32 pids should be enough for everyone.
- snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
- write_file(file, "32");
- // Restrict memory consumption.
- // We have some syscalls that inherently consume lots of memory,
- // e.g. mounting some filesystem images requires at least 128MB
- // image in memory. We restrict RLIMIT_AS to 200MB. Here we gradually
- // increase low/high/max limits to make things more interesting.
- // Also this takes into account KASAN quarantine size.
- // If the limit is lower than KASAN quarantine size, then it can happen
- // so that we kill the process, but all of its memory is in quarantine
- // and is still accounted against memcg. As the result memcg won't
- // allow to allocate any memory in the parent and in the new test process.
- // The current limit of 300MB supports up to 9.6GB RAM (quarantine is 1/32).
- snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
- write_file(file, "%d", 298 << 20);
- snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
- write_file(file, "%d", 299 << 20);
- snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
- write_file(file, "%d", 300 << 20);
- // Setup some v1 groups to make things more interesting.
- snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
- write_file(file, "%d", pid);
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
- if (mkdir(cgroupdir, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
- }
- snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
- write_file(file, "%d", pid);
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
- if (mkdir(cgroupdir, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
- }
- snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
- write_file(file, "%d", pid);
+ setup_cgroups_loop();
#endif
#if SYZ_EXECUTOR || SYZ_RESET_NET_NAMESPACE
checkpoint_net_namespace();
@@ -2534,22 +2602,10 @@ static void setup_test()
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setpgrp();
#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
- char cgroupdir[64];
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
- if (symlink(cgroupdir, "./cgroup")) {
- debug("symlink(%s, ./cgroup) failed: %d\n", cgroupdir, errno);
- }
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
- if (symlink(cgroupdir, "./cgroup.cpu")) {
- debug("symlink(%s, ./cgroup.cpu) failed: %d\n", cgroupdir, errno);
- }
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
- if (symlink(cgroupdir, "./cgroup.net")) {
- debug("symlink(%s, ./cgroup.net) failed: %d\n", cgroupdir, errno);
- }
+ setup_cgroups_test();
+#endif
// It's the leaf test process we want to be always killed first.
write_file("/proc/self/oom_score_adj", "1000");
-#endif
#if SYZ_EXECUTOR || SYZ_TUN_ENABLE
// Read all remaining packets from tun to better
// isolate consequently executing programs.
diff --git a/executor/executor.cc b/executor/executor.cc
index 22a728905..f1f6ba294 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -112,10 +112,13 @@ uint64 start_time_ms = 0;
static bool flag_debug;
static bool flag_cover;
static sandbox_type flag_sandbox;
+static bool flag_extra_cover;
+static bool flag_enable_fault_injection;
static bool flag_enable_tun;
static bool flag_enable_net_dev;
-static bool flag_enable_fault_injection;
-static bool flag_extra_cover;
+static bool flag_enable_net_reset;
+static bool flag_enable_cgroups;
+static bool flag_enable_binfmt_misc;
static bool flag_collect_cover;
static bool flag_dedup_cover;
@@ -444,10 +447,13 @@ void parse_env_flags(uint64 flags)
flag_sandbox = sandbox_namespace;
else if (flags & (1 << 4))
flag_sandbox = sandbox_android_untrusted_app;
- flag_enable_tun = flags & (1 << 5);
- flag_enable_net_dev = flags & (1 << 6);
- flag_enable_fault_injection = flags & (1 << 7);
- flag_extra_cover = flags & (1 << 8);
+ flag_extra_cover = flags & (1 << 5);
+ flag_enable_fault_injection = flags & (1 << 6);
+ flag_enable_tun = flags & (1 << 7);
+ flag_enable_net_dev = flags & (1 << 8);
+ flag_enable_net_reset = flags & (1 << 9);
+ flag_enable_cgroups = flags & (1 << 10);
+ flag_enable_binfmt_misc = flags & (1 << 11);
}
#if SYZ_EXECUTOR_USES_FORK_SERVER
diff --git a/pkg/csource/common.go b/pkg/csource/common.go
index 9de387952..a39d714e0 100644
--- a/pkg/csource/common.go
+++ b/pkg/csource/common.go
@@ -82,8 +82,9 @@ func defineList(p, mmapProg *prog.Prog, opts Options) (defines []string) {
"SYZ_FAULT_INJECTION": opts.Fault,
"SYZ_TUN_ENABLE": opts.EnableTun,
"SYZ_ENABLE_CGROUPS": opts.EnableCgroups,
- "SYZ_ENABLE_NETDEV": opts.EnableNetdev,
- "SYZ_RESET_NET_NAMESPACE": opts.ResetNet,
+ "SYZ_ENABLE_NETDEV": opts.EnableNetDev,
+ "SYZ_RESET_NET_NAMESPACE": opts.EnableNetReset,
+ "SYZ_ENABLE_BINFMT_MISC": opts.EnableBinfmtMisc,
"SYZ_USE_TMP_DIR": opts.UseTmpDir,
"SYZ_HANDLE_SEGV": opts.HandleSegv,
"SYZ_REPRO": opts.Repro,
diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go
index f58bf8e30..fbbd671bf 100644
--- a/pkg/csource/generated.go
+++ b/pkg/csource/generated.go
@@ -208,6 +208,7 @@ static int inject_fault(int nth)
return 0;
}
#endif
+
#if SYZ_EXECUTOR
static int fault_injected(int fail_fd)
{
@@ -1051,7 +1052,7 @@ static int event_timedwait(event_t* ev, uint64 timeout)
}
#endif
-#if SYZ_EXECUTOR || SYZ_FAULT_INJECTION || SYZ_ENABLE_CGROUPS || SYZ_SANDBOX_NONE || \
+#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
#include <errno.h>
#include <fcntl.h>
@@ -3492,6 +3493,8 @@ static void reset_ebtables()
static void checkpoint_net_namespace(void)
{
#if SYZ_EXECUTOR
+ if (!flag_enable_net_reset)
+ return;
if (flag_sandbox == sandbox_setuid)
return;
#endif
@@ -3504,6 +3507,8 @@ static void checkpoint_net_namespace(void)
static void reset_net_namespace(void)
{
#if SYZ_EXECUTOR
+ if (!flag_enable_net_reset)
+ return;
if (flag_sandbox == sandbox_setuid)
return;
#endif
@@ -3514,7 +3519,7 @@ static void reset_net_namespace(void)
}
#endif
-#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
+#if SYZ_EXECUTOR || (SYZ_ENABLE_CGROUPS && (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>
@@ -3522,6 +3527,10 @@ static void reset_net_namespace(void)
static void setup_cgroups()
{
+#if SYZ_EXECUTOR
+ if (!flag_enable_cgroups)
+ return;
+#endif
if (mkdir("/syzcgroup", 0777)) {
debug("mkdir(/syzcgroup) failed: %d\n", errno);
}
@@ -3555,8 +3564,108 @@ static void setup_cgroups()
debug("chmod(/syzcgroup/net) failed: %d\n", errno);
}
}
+
+#if SYZ_EXECUTOR || SYZ_REPEAT
+static void setup_cgroups_loop()
+{
+#if SYZ_EXECUTOR
+ if (!flag_enable_cgroups)
+ return;
+#endif
+ int pid = getpid();
+ char file[128];
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
+ write_file(file, "32");
+ snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
+ write_file(file, "%d", 298 << 20);
+ snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
+ write_file(file, "%d", 299 << 20);
+ snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
+ write_file(file, "%d", 300 << 20);
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (mkdir(cgroupdir, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
+ write_file(file, "%d", pid);
+}
+
+static void setup_cgroups_test()
+{
+#if SYZ_EXECUTOR
+ if (!flag_enable_cgroups)
+ return;
+#endif
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup")) {
+ debug("symlink(%s, ./cgroup) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.cpu")) {
+ debug("symlink(%s, ./cgroup.cpu) failed: %d\n", cgroupdir, errno);
+ }
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
+ if (symlink(cgroupdir, "./cgroup.net")) {
+ debug("symlink(%s, ./cgroup.net) failed: %d\n", cgroupdir, errno);
+ }
+}
+#endif
+
+#if SYZ_EXECUTOR || SYZ_SANDBOX_NAMESPACE
+void initialize_cgroups()
+{
+#if SYZ_EXECUTOR
+ if (!flag_enable_cgroups)
+ return;
+#endif
+ if (mkdir("./syz-tmp/newroot/syzcgroup", 0700))
+ fail("mkdir failed");
+ if (mkdir("./syz-tmp/newroot/syzcgroup/unified", 0700))
+ fail("mkdir failed");
+ if (mkdir("./syz-tmp/newroot/syzcgroup/cpu", 0700))
+ fail("mkdir failed");
+ if (mkdir("./syz-tmp/newroot/syzcgroup/net", 0700))
+ fail("mkdir failed");
+ unsigned bind_mount_flags = MS_BIND | MS_REC | MS_PRIVATE;
+ if (mount("/syzcgroup/unified", "./syz-tmp/newroot/syzcgroup/unified", NULL, bind_mount_flags, NULL)) {
+ debug("mount(cgroup2, MS_BIND) failed: %d\n", errno);
+ }
+ if (mount("/syzcgroup/cpu", "./syz-tmp/newroot/syzcgroup/cpu", NULL, bind_mount_flags, NULL)) {
+ debug("mount(cgroup/cpu, MS_BIND) failed: %d\n", errno);
+ }
+ if (mount("/syzcgroup/net", "./syz-tmp/newroot/syzcgroup/net", NULL, bind_mount_flags, NULL)) {
+ debug("mount(cgroup/net, MS_BIND) failed: %d\n", errno);
+ }
+}
+#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);
}
@@ -3576,6 +3685,8 @@ static void setup_common()
}
#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
setup_cgroups();
+#endif
+#if SYZ_EXECUTOR || SYZ_ENABLE_BINFMT_MISC
setup_binfmt_misc();
#endif
}
@@ -3802,23 +3913,7 @@ static int namespace_sandbox_proc(void* arg)
if (mount("/sys", "./syz-tmp/newroot/sys", 0, bind_mount_flags, NULL))
fail("mount(sysfs) failed");
#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
- if (mkdir("./syz-tmp/newroot/syzcgroup", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/unified", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/cpu", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/net", 0700))
- fail("mkdir failed");
- if (mount("/syzcgroup/unified", "./syz-tmp/newroot/syzcgroup/unified", NULL, bind_mount_flags, NULL)) {
- debug("mount(cgroup2, MS_BIND) failed: %d\n", errno);
- }
- if (mount("/syzcgroup/cpu", "./syz-tmp/newroot/syzcgroup/cpu", NULL, bind_mount_flags, NULL)) {
- debug("mount(cgroup/cpu, MS_BIND) failed: %d\n", errno);
- }
- if (mount("/syzcgroup/net", "./syz-tmp/newroot/syzcgroup/net", NULL, bind_mount_flags, NULL)) {
- debug("mount(cgroup/net, MS_BIND) failed: %d\n", errno);
- }
+ initialize_cgroups();
#endif
if (mkdir("./syz-tmp/pivot", 0777))
fail("mkdir failed");
@@ -4090,12 +4185,15 @@ retry:
static int inject_fault(int nth)
{
+#if SYZ_EXECUTOR
+ if (!flag_enable_fault_injection)
+ return 0;
+#endif
int fd;
- char buf[16];
-
fd = open("/proc/thread-self/fail-nth", O_RDWR);
if (fd == -1)
exitf("failed to open /proc/thread-self/fail-nth");
+ char buf[16];
sprintf(buf, "%d", nth + 1);
if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
exitf("failed to write /proc/thread-self/fail-nth");
@@ -4106,6 +4204,8 @@ 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)
@@ -4181,35 +4281,7 @@ static void kill_and_wait(int pid, int* status)
static void setup_loop()
{
#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
- int pid = getpid();
- char cgroupdir[64];
- char file[128];
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
- if (mkdir(cgroupdir, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
- }
- snprintf(file, sizeof(file), "%s/pids.max", cgroupdir);
- write_file(file, "32");
- snprintf(file, sizeof(file), "%s/memory.low", cgroupdir);
- write_file(file, "%d", 298 << 20);
- snprintf(file, sizeof(file), "%s/memory.high", cgroupdir);
- write_file(file, "%d", 299 << 20);
- snprintf(file, sizeof(file), "%s/memory.max", cgroupdir);
- write_file(file, "%d", 300 << 20);
- snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
- write_file(file, "%d", pid);
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
- if (mkdir(cgroupdir, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
- }
- snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
- write_file(file, "%d", pid);
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
- if (mkdir(cgroupdir, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
- }
- snprintf(file, sizeof(file), "%s/cgroup.procs", cgroupdir);
- write_file(file, "%d", pid);
+ setup_cgroups_loop();
#endif
#if SYZ_EXECUTOR || SYZ_RESET_NET_NAMESPACE
checkpoint_net_namespace();
@@ -4245,21 +4317,9 @@ static void setup_test()
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setpgrp();
#if SYZ_EXECUTOR || SYZ_ENABLE_CGROUPS
- char cgroupdir[64];
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
- if (symlink(cgroupdir, "./cgroup")) {
- debug("symlink(%s, ./cgroup) failed: %d\n", cgroupdir, errno);
- }
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/cpu/syz%llu", procid);
- if (symlink(cgroupdir, "./cgroup.cpu")) {
- debug("symlink(%s, ./cgroup.cpu) failed: %d\n", cgroupdir, errno);
- }
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/net/syz%llu", procid);
- if (symlink(cgroupdir, "./cgroup.net")) {
- debug("symlink(%s, ./cgroup.net) failed: %d\n", cgroupdir, errno);
- }
- write_file("/proc/self/oom_score_adj", "1000");
+ setup_cgroups_test();
#endif
+ write_file("/proc/self/oom_score_adj", "1000");
#if SYZ_EXECUTOR || SYZ_TUN_ENABLE
flush_tun();
#endif
diff --git a/pkg/csource/options.go b/pkg/csource/options.go
index 4a0cc9fbc..d82ff28bd 100644
--- a/pkg/csource/options.go
+++ b/pkg/csource/options.go
@@ -8,6 +8,8 @@ import (
"encoding/json"
"errors"
"fmt"
+ "sort"
+ "strings"
"github.com/google/syzkaller/pkg/mgrconfig"
)
@@ -27,12 +29,14 @@ type Options struct {
FaultNth int `json:"fault_nth,omitempty"`
// These options allow for a more fine-tuned control over the generated C code.
- EnableTun bool `json:"tun,omitempty"`
- UseTmpDir bool `json:"tmpdir,omitempty"`
- EnableCgroups bool `json:"cgroups,omitempty"`
- EnableNetdev bool `json:"netdev,omitempty"`
- ResetNet bool `json:"resetnet,omitempty"`
- HandleSegv bool `json:"segv,omitempty"`
+ EnableTun bool `json:"tun,omitempty"`
+ EnableNetDev bool `json:"netdev,omitempty"`
+ EnableNetReset bool `json:"resetnet,omitempty"`
+ EnableCgroups bool `json:"cgroups,omitempty"`
+ EnableBinfmtMisc bool `json:"binfmt_misc,omitempty"`
+
+ UseTmpDir bool `json:"tmpdir,omitempty"`
+ HandleSegv bool `json:"segv,omitempty"`
// Generate code for use with repro package to prints log messages,
// which allows to detect hangs.
@@ -58,8 +62,8 @@ func (opts Options) Check(OS string) error {
// This does not affect generated code.
return errors.New("Procs>1 without Repeat")
}
- if opts.ResetNet {
- return errors.New("ResetNet without Repeat")
+ if opts.EnableNetReset {
+ return errors.New("EnableNetReset without Repeat")
}
if opts.RepeatTimes > 1 {
return errors.New("RepeatTimes without Repeat")
@@ -69,11 +73,14 @@ func (opts Options) Check(OS string) error {
if opts.EnableTun {
return errors.New("EnableTun without sandbox")
}
+ if opts.EnableNetDev {
+ return errors.New("EnableNetDev without sandbox")
+ }
if opts.EnableCgroups {
return errors.New("EnableCgroups without sandbox")
}
- if opts.EnableNetdev {
- return errors.New("EnableNetdev without sandbox")
+ if opts.EnableBinfmtMisc {
+ return errors.New("EnableBinfmtMisc without sandbox")
}
}
if opts.Sandbox == sandboxNamespace && !opts.UseTmpDir {
@@ -82,12 +89,12 @@ func (opts Options) Check(OS string) error {
// which will fail if procs>1 and on second run of the program.
return errors.New("Sandbox=namespace without UseTmpDir")
}
+ if opts.EnableNetReset && (opts.Sandbox == "" || opts.Sandbox == sandboxSetuid) {
+ return errors.New("EnableNetReset without sandbox")
+ }
if opts.EnableCgroups && !opts.UseTmpDir {
return errors.New("EnableCgroups without UseTmpDir")
}
- if opts.ResetNet && (opts.Sandbox == "" || opts.Sandbox == sandboxSetuid) {
- return errors.New("ResetNet without sandbox")
- }
return opts.checkLinuxOnly(OS)
}
@@ -98,14 +105,17 @@ func (opts Options) checkLinuxOnly(OS string) error {
if opts.EnableTun && !(OS == "openbsd" || OS == "freebsd") {
return fmt.Errorf("EnableTun is not supported on %v", OS)
}
+ if opts.EnableNetDev {
+ return fmt.Errorf("EnableNetDev is not supported on %v", OS)
+ }
+ if opts.EnableNetReset {
+ return fmt.Errorf("EnableNetReset is not supported on %v", OS)
+ }
if opts.EnableCgroups {
return fmt.Errorf("EnableCgroups is not supported on %v", OS)
}
- if opts.EnableNetdev {
- return fmt.Errorf("EnableNetdev is not supported on %v", OS)
- }
- if opts.ResetNet {
- return fmt.Errorf("ResetNet is not supported on %v", OS)
+ if opts.EnableBinfmtMisc {
+ return fmt.Errorf("EnableBinfmtMisc is not supported on %v", OS)
}
if opts.Sandbox == sandboxNamespace ||
(opts.Sandbox == sandboxSetuid && !(OS == "openbsd" || OS == "freebsd")) ||
@@ -120,27 +130,29 @@ func (opts Options) checkLinuxOnly(OS string) error {
func DefaultOpts(cfg *mgrconfig.Config) Options {
opts := Options{
- Threaded: true,
- Collide: true,
- Repeat: true,
- Procs: cfg.Procs,
- Sandbox: cfg.Sandbox,
- EnableTun: true,
- EnableCgroups: true,
- EnableNetdev: true,
- ResetNet: true,
- UseTmpDir: true,
- HandleSegv: true,
- Repro: true,
+ Threaded: true,
+ Collide: true,
+ Repeat: true,
+ Procs: cfg.Procs,
+ Sandbox: cfg.Sandbox,
+ EnableTun: true,
+ EnableNetDev: true,
+ EnableNetReset: true,
+ EnableCgroups: true,
+ EnableBinfmtMisc: true,
+ UseTmpDir: true,
+ HandleSegv: true,
+ Repro: true,
}
if cfg.TargetOS != linux {
opts.EnableTun = false
+ opts.EnableNetDev = false
+ opts.EnableNetReset = false
opts.EnableCgroups = false
- opts.EnableNetdev = false
- opts.ResetNet = false
+ opts.EnableBinfmtMisc = false
}
if cfg.Sandbox == "" || cfg.Sandbox == "setuid" {
- opts.ResetNet = false
+ opts.EnableNetReset = false
}
if err := opts.Check(cfg.TargetOS); err != nil {
panic(fmt.Sprintf("DefaultOpts created bad opts: %v", err))
@@ -198,3 +210,66 @@ func DeserializeOptions(data []byte) (Options, error) {
}
return opts, err
}
+
+type Feature struct {
+ Description string
+ Enabled bool
+}
+
+type Features map[string]Feature
+
+func defaultFeatures(value bool) Features {
+ return map[string]Feature{
+ "tun": {"setup and use /dev/tun for packet injection", value},
+ "net_dev": {"setup more network devices for testing", value},
+ "net_reset": {"reset network namespace between programs", value},
+ "cgroups": {"setup cgroups for testing", value},
+ "binfmt_misc": {"setup binfmt_misc for testing", value},
+ }
+}
+
+func ParseFeaturesFlags(enable string, disable string, defaultValue bool) (Features, error) {
+ if enable == "none" && disable == "none" {
+ return defaultFeatures(defaultValue), nil
+ }
+ if enable != "none" && disable != "none" {
+ return nil, fmt.Errorf("can't use -enable and -disable flags at the same time")
+ }
+ if enable == "all" || disable == "" {
+ return defaultFeatures(true), nil
+ }
+ if disable == "all" || enable == "" {
+ return defaultFeatures(false), nil
+ }
+ var items []string
+ var features Features
+ if enable != "none" {
+ items = strings.Split(enable, ",")
+ features = defaultFeatures(false)
+ } else {
+ items = strings.Split(disable, ",")
+ features = defaultFeatures(true)
+ }
+ for _, item := range items {
+ if _, ok := features[item]; !ok {
+ return nil, fmt.Errorf("unknown feature specified: %s", item)
+ }
+ feature := features[item]
+ feature.Enabled = (enable != "none")
+ features[item] = feature
+ }
+ return features, nil
+}
+
+func PrintAvailableFeaturesFlags() {
+ fmt.Printf("Available features for -enable and -disable:\n")
+ features := defaultFeatures(false)
+ var names []string
+ for name := range features {
+ names = append(names, name)
+ }
+ sort.Strings(names)
+ for _, name := range names {
+ fmt.Printf(" %s - %s\n", name, features[name].Description)
+ }
+}
diff --git a/pkg/csource/options_test.go b/pkg/csource/options_test.go
index d8e8a217e..0240208e0 100644
--- a/pkg/csource/options_test.go
+++ b/pkg/csource/options_test.go
@@ -31,86 +31,91 @@ func TestParseOptionsCanned(t *testing.T) {
"fault":true,"fault_call":1,"fault_nth":2,"tun":true,"tmpdir":true,"cgroups":true,
"netdev":true,"resetnet":true,
"segv":true,"waitrepeat":true,"debug":true,"repro":true}`: {
- Threaded: true,
- Collide: true,
- Repeat: true,
- Procs: 10,
- Sandbox: "namespace",
- Fault: true,
- FaultCall: 1,
- FaultNth: 2,
- EnableTun: true,
- UseTmpDir: true,
- EnableCgroups: true,
- EnableNetdev: true,
- ResetNet: true,
- HandleSegv: true,
- Repro: true,
+ Threaded: true,
+ Collide: true,
+ Repeat: true,
+ Procs: 10,
+ Sandbox: "namespace",
+ Fault: true,
+ FaultCall: 1,
+ FaultNth: 2,
+ EnableTun: true,
+ EnableNetDev: true,
+ EnableNetReset: true,
+ EnableCgroups: true,
+ EnableBinfmtMisc: false,
+ UseTmpDir: true,
+ HandleSegv: true,
+ Repro: true,
},
`{"threaded":true,"collide":true,"repeat":true,"procs":10,"sandbox":"android_untrusted_app",
"fault":true,"fault_call":1,"fault_nth":2,"tun":true,"tmpdir":true,"cgroups":true,
"netdev":true,"resetnet":true,
"segv":true,"waitrepeat":true,"debug":true,"repro":true}`: {
- Threaded: true,
- Collide: true,
- Repeat: true,
- Procs: 10,
- Sandbox: "android_untrusted_app",
- Fault: true,
- FaultCall: 1,
- FaultNth: 2,
- EnableTun: true,
- UseTmpDir: true,
- EnableCgroups: true,
- EnableNetdev: true,
- ResetNet: true,
- HandleSegv: true,
- Repro: true,
+ Threaded: true,
+ Collide: true,
+ Repeat: true,
+ Procs: 10,
+ Sandbox: "android_untrusted_app",
+ Fault: true,
+ FaultCall: 1,
+ FaultNth: 2,
+ EnableTun: true,
+ EnableNetDev: true,
+ EnableNetReset: true,
+ EnableCgroups: true,
+ EnableBinfmtMisc: false,
+ UseTmpDir: true,
+ HandleSegv: true,
+ Repro: true,
},
"{Threaded:true Collide:true Repeat:true Procs:1 Sandbox:none Fault:false FaultCall:-1 FaultNth:0 EnableTun:true UseTmpDir:true HandleSegv:true WaitRepeat:true Debug:false Repro:false}": {
- Threaded: true,
- Collide: true,
- Repeat: true,
- Procs: 1,
- Sandbox: "none",
- Fault: false,
- FaultCall: -1,
- FaultNth: 0,
- EnableTun: true,
- UseTmpDir: true,
- EnableCgroups: false,
- HandleSegv: true,
- Repro: false,
+ Threaded: true,
+ Collide: true,
+ Repeat: true,
+ Procs: 1,
+ Sandbox: "none",
+ Fault: false,
+ FaultCall: -1,
+ FaultNth: 0,
+ EnableTun: true,
+ EnableCgroups: false,
+ EnableBinfmtMisc: false,
+ UseTmpDir: true,
+ HandleSegv: true,
+ Repro: false,
},
"{Threaded:true Collide:true Repeat:true Procs:1 Sandbox: Fault:false FaultCall:-1 FaultNth:0 EnableTun:true UseTmpDir:true HandleSegv:true WaitRepeat:true Debug:false Repro:false}": {
- Threaded: true,
- Collide: true,
- Repeat: true,
- Procs: 1,
- Sandbox: "",
- Fault: false,
- FaultCall: -1,
- FaultNth: 0,
- EnableTun: true,
- UseTmpDir: true,
- EnableCgroups: false,
- HandleSegv: true,
- Repro: false,
+ Threaded: true,
+ Collide: true,
+ Repeat: true,
+ Procs: 1,
+ Sandbox: "",
+ Fault: false,
+ FaultCall: -1,
+ FaultNth: 0,
+ EnableTun: true,
+ EnableCgroups: false,
+ EnableBinfmtMisc: false,
+ UseTmpDir: true,
+ HandleSegv: true,
+ Repro: false,
},
"{Threaded:false Collide:true Repeat:true Procs:1 Sandbox:namespace Fault:false FaultCall:-1 FaultNth:0 EnableTun:true UseTmpDir:true EnableCgroups:true HandleSegv:true WaitRepeat:true Debug:false Repro:false}": {
- Threaded: false,
- Collide: true,
- Repeat: true,
- Procs: 1,
- Sandbox: "namespace",
- Fault: false,
- FaultCall: -1,
- FaultNth: 0,
- EnableTun: true,
- UseTmpDir: true,
- EnableCgroups: true,
- HandleSegv: true,
- Repro: false,
+ Threaded: false,
+ Collide: true,
+ Repeat: true,
+ Procs: 1,
+ Sandbox: "namespace",
+ Fault: false,
+ FaultCall: -1,
+ FaultNth: 0,
+ EnableTun: true,
+ EnableCgroups: true,
+ EnableBinfmtMisc: false,
+ UseTmpDir: true,
+ HandleSegv: true,
+ Repro: false,
},
}
for data, want := range canned {
@@ -194,3 +199,49 @@ func enumerateField(OS string, opt Options, field int) []Options {
}
return checked
}
+
+func TestParseFeaturesFlags(t *testing.T) {
+ tests := []struct {
+ Enable string
+ Disable string
+ Default bool
+ Features map[string]bool
+ }{
+ {"none", "none", true, map[string]bool{
+ "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true,
+ }},
+ {"none", "none", false, map[string]bool{
+ "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false,
+ }},
+ {"all", "none", true, map[string]bool{
+ "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true,
+ }},
+ {"", "none", true, map[string]bool{
+ "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false,
+ }},
+ {"none", "all", true, map[string]bool{
+ "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false,
+ }},
+ {"none", "", true, map[string]bool{
+ "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true,
+ }},
+ {"tun,net_dev", "none", true, map[string]bool{
+ "tun": true, "net_dev": true, "net_reset": false, "cgroups": false, "binfmt_misc": false,
+ }},
+ {"none", "cgroups,net_dev", true, map[string]bool{
+ "tun": true, "net_dev": false, "net_reset": true, "cgroups": false, "binfmt_misc": true,
+ }},
+ }
+ for i, test := range tests {
+ features, err := ParseFeaturesFlags(test.Enable, test.Disable, test.Default)
+ if err != nil {
+ t.Fatalf("failed to parse features flags: %v", err)
+ }
+ for name, feature := range features {
+ if feature.Enabled != test.Features[name] {
+ t.Fatalf("test #%v: invalid value for feature flag %s: got %v, want %v",
+ i, name, feature.Enabled, test.Features[name])
+ }
+ }
+ }
+}
diff --git a/pkg/ipc/ipc.go b/pkg/ipc/ipc.go
index b2d4c9d63..e1e22445e 100644
--- a/pkg/ipc/ipc.go
+++ b/pkg/ipc/ipc.go
@@ -31,10 +31,13 @@ const (
FlagSandboxSetuid // impersonate nobody user
FlagSandboxNamespace // use namespaces for sandboxing
FlagSandboxAndroidUntrustedApp // use Android sandboxing for the untrusted_app domain
- FlagEnableTun // initialize and use tun in executor
- FlagEnableNetDev // setup a bunch of various network devices for testing
- FlagEnableFault // enable fault injection support
FlagExtraCover // collect extra coverage
+ FlagEnableFault // enable fault injection support
+ FlagEnableTun // setup and use /dev/tun for packet injection
+ FlagEnableNetDev // setup more network devices for testing
+ FlagEnableNetReset // reset network namespace between programs
+ FlagEnableCgroups // setup cgroups for testing
+ FlagEnableBinfmtMisc // setup binfmt_misc for testing
// Executor does not know about these:
FlagUseShmem // use shared memory instead of pipes for communication
FlagUseForkServer // use extended protocol with handshake
diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go
index ab91e545a..2c6a0e6ed 100644
--- a/pkg/repro/repro.go
+++ b/pkg/repro/repro.go
@@ -777,7 +777,7 @@ var progSimplifies = []Simplify{
}
opts.Repeat = false
opts.EnableCgroups = false
- opts.ResetNet = false
+ opts.EnableNetReset = false
opts.Procs = 1
return true
},
@@ -804,9 +804,10 @@ var cSimplifies = append(progSimplifies, []Simplify{
}
opts.Sandbox = ""
opts.EnableTun = false
+ opts.EnableNetDev = false
+ opts.EnableNetReset = false
opts.EnableCgroups = false
- opts.EnableNetdev = false
- opts.ResetNet = false
+ opts.EnableBinfmtMisc = false
return true
},
func(opts *csource.Options) bool {
@@ -817,24 +818,31 @@ var cSimplifies = append(progSimplifies, []Simplify{
return true
},
func(opts *csource.Options) bool {
- if !opts.EnableCgroups {
+ if !opts.EnableNetDev {
return false
}
- opts.EnableCgroups = false
+ opts.EnableNetDev = false
return true
},
func(opts *csource.Options) bool {
- if !opts.EnableNetdev {
+ if !opts.EnableNetReset {
return false
}
- opts.EnableNetdev = false
+ opts.EnableNetReset = false
+ return true
+ },
+ func(opts *csource.Options) bool {
+ if !opts.EnableCgroups {
+ return false
+ }
+ opts.EnableCgroups = false
return true
},
func(opts *csource.Options) bool {
- if !opts.ResetNet {
+ if !opts.EnableBinfmtMisc {
return false
}
- opts.ResetNet = false
+ opts.EnableBinfmtMisc = false
return true
},
func(opts *csource.Options) bool {
diff --git a/pkg/repro/repro_test.go b/pkg/repro/repro_test.go
index 349b412fc..c417b7416 100644
--- a/pkg/repro/repro_test.go
+++ b/pkg/repro/repro_test.go
@@ -73,18 +73,18 @@ func TestBisect(t *testing.T) {
func TestSimplifies(t *testing.T) {
opts := csource.Options{
- Threaded: true,
- Collide: true,
- Repeat: true,
- Procs: 10,
- Sandbox: "namespace",
- EnableTun: true,
- EnableCgroups: true,
- EnableNetdev: true,
- ResetNet: true,
- UseTmpDir: true,
- HandleSegv: true,
- Repro: true,
+ Threaded: true,
+ Collide: true,
+ Repeat: true,
+ Procs: 10,
+ Sandbox: "namespace",
+ EnableTun: true,
+ EnableNetDev: true,
+ EnableNetReset: true,
+ EnableCgroups: true,
+ UseTmpDir: true,
+ HandleSegv: true,
+ Repro: true,
}
var check func(opts csource.Options, i int)
check = func(opts csource.Options, i int) {
diff --git a/pkg/runtest/run.go b/pkg/runtest/run.go
index 0af03158e..13195dc36 100644
--- a/pkg/runtest/run.go
+++ b/pkg/runtest/run.go
@@ -349,6 +349,8 @@ func (ctx *Context) createSyzTest(p *prog.Prog, sandbox string, threaded, cov bo
if ctx.Features[host.FeatureNetworkDevices].Enabled {
cfg.Flags |= ipc.FlagEnableNetDev
}
+ cfg.Flags |= ipc.FlagEnableNetReset
+ cfg.Flags |= ipc.FlagEnableCgroups
req := &RunRequest{
P: p,
Cfg: cfg,
@@ -376,7 +378,7 @@ func (ctx *Context) createCTest(p *prog.Prog, sandbox string, threaded bool, tim
opts.EnableTun = true
}
if ctx.Features[host.FeatureNetworkDevices].Enabled {
- opts.EnableNetdev = true
+ opts.EnableNetDev = true
}
}
src, err := csource.Write(p, opts)
diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go
index d41dfe661..52fa30def 100644
--- a/syz-fuzzer/fuzzer.go
+++ b/syz-fuzzer/fuzzer.go
@@ -190,15 +190,18 @@ func main() {
if r.CheckResult.Features[host.FeatureExtraCoverage].Enabled {
config.Flags |= ipc.FlagExtraCover
}
+ if r.CheckResult.Features[host.FeatureFaultInjection].Enabled {
+ config.Flags |= ipc.FlagEnableFault
+ }
if r.CheckResult.Features[host.FeatureNetworkInjection].Enabled {
config.Flags |= ipc.FlagEnableTun
}
if r.CheckResult.Features[host.FeatureNetworkDevices].Enabled {
config.Flags |= ipc.FlagEnableNetDev
}
- if r.CheckResult.Features[host.FeatureFaultInjection].Enabled {
- config.Flags |= ipc.FlagEnableFault
- }
+ config.Flags |= ipc.FlagEnableNetReset
+ config.Flags |= ipc.FlagEnableCgroups
+ config.Flags |= ipc.FlagEnableBinfmtMisc
if *flagRunTest {
runTest(target, manager, *flagName, config.Executor)
diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go
index f65ad9d9b..bfc50beaf 100644
--- a/tools/syz-execprog/execprog.go
+++ b/tools/syz-execprog/execprog.go
@@ -16,6 +16,7 @@ import (
"time"
"github.com/google/syzkaller/pkg/cover"
+ "github.com/google/syzkaller/pkg/csource"
"github.com/google/syzkaller/pkg/host"
"github.com/google/syzkaller/pkg/ipc"
"github.com/google/syzkaller/pkg/ipc/ipcconfig"
@@ -32,29 +33,37 @@ var (
flagRepeat = flag.Int("repeat", 1, "repeat execution that many times (0 for infinite loop)")
flagProcs = flag.Int("procs", 1, "number of parallel processes to execute programs")
flagOutput = flag.Bool("output", false, "write programs and results to stdout")
+ flagHints = flag.Bool("hints", false, "do a hints-generation run")
flagFaultCall = flag.Int("fault_call", -1, "inject fault into this call (0-based)")
flagFaultNth = flag.Int("fault_nth", 0, "inject fault on n-th operation (0-based)")
- flagHints = flag.Bool("hints", false, "do a hints-generation run")
+ flagEnable = flag.String("enable", "none", "enable only listed additional features")
+ flagDisable = flag.String("disable", "none", "enable all additional features except listed")
)
func main() {
- flag.Parse()
- if len(flag.Args()) == 0 {
+ flag.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs+\n")
flag.PrintDefaults()
+ csource.PrintAvailableFeaturesFlags()
+ }
+ flag.Parse()
+ if len(flag.Args()) == 0 {
+ flag.Usage()
os.Exit(1)
}
+ featuresFlags, err := csource.ParseFeaturesFlags(*flagEnable, *flagDisable, true)
+ if err != nil {
+ log.Fatalf("%v", err)
+ }
target, err := prog.GetTarget(*flagOS, *flagArch)
if err != nil {
log.Fatalf("%v", err)
}
-
entries := loadPrograms(target, flag.Args())
if len(entries) == 0 {
return
}
-
features, err := host.Check(target)
if err != nil {
log.Fatalf("%v", err)
@@ -67,7 +76,7 @@ func main() {
if _, err = host.Setup(target, features); err != nil {
log.Fatalf("%v", err)
}
- config, execOpts := createConfig(target, entries, features)
+ config, execOpts := createConfig(target, entries, features, featuresFlags)
ctx := &Context{
entries: entries,
@@ -264,7 +273,8 @@ func loadPrograms(target *prog.Target, files []string) []*prog.LogEntry {
return entries
}
-func createConfig(target *prog.Target, entries []*prog.LogEntry, features *host.Features) (
+func createConfig(target *prog.Target, entries []*prog.LogEntry,
+ features *host.Features, featuresFlags csource.Features) (
*ipc.Config, *ipc.ExecOpts) {
config, execOpts, err := ipcconfig.Default(target)
if err != nil {
@@ -299,11 +309,20 @@ func createConfig(target *prog.Target, entries []*prog.LogEntry, features *host.
handled[call.Meta.CallName] = true
}
}
- if features[host.FeatureNetworkInjection].Enabled {
+ if featuresFlags["tun"].Enabled && features[host.FeatureNetworkInjection].Enabled {
config.Flags |= ipc.FlagEnableTun
}
- if features[host.FeatureNetworkDevices].Enabled {
+ if featuresFlags["net_dev"].Enabled && features[host.FeatureNetworkDevices].Enabled {
config.Flags |= ipc.FlagEnableNetDev
}
+ if featuresFlags["net_reset"].Enabled {
+ config.Flags |= ipc.FlagEnableNetReset
+ }
+ if featuresFlags["cgroups"].Enabled {
+ config.Flags |= ipc.FlagEnableCgroups
+ }
+ if featuresFlags["binfmt_misc"].Enabled {
+ config.Flags |= ipc.FlagEnableBinfmtMisc
+ }
return config, execOpts
}
diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go
index d45c1e5a8..d076ad2ee 100644
--- a/tools/syz-prog2c/prog2c.go
+++ b/tools/syz-prog2c/prog2c.go
@@ -7,6 +7,7 @@ import (
"flag"
"fmt"
"io/ioutil"
+ "log"
"os"
"runtime"
@@ -27,22 +28,28 @@ var (
flagProg = flag.String("prog", "", "file with program to convert (required)")
flagFaultCall = flag.Int("fault_call", -1, "inject fault into this call (0-based)")
flagFaultNth = flag.Int("fault_nth", 0, "inject fault on n-th operation (0-based)")
- flagEnableTun = flag.Bool("tun", false, "set up TUN/TAP interface")
- flagUseTmpDir = flag.Bool("tmpdir", false, "create a temporary dir and execute inside it")
- flagCgroups = flag.Bool("cgroups", false, "enable cgroups support")
- flagNetdev = flag.Bool("netdev", false, "setup various net devices")
- flagResetNet = flag.Bool("resetnet", false, "reset net namespace after each test")
flagHandleSegv = flag.Bool("segv", false, "catch and ignore SIGSEGV")
+ flagUseTmpDir = flag.Bool("tmpdir", false, "create a temporary dir and execute inside it")
flagTrace = flag.Bool("trace", false, "trace syscall results")
flagStrict = flag.Bool("strict", false, "parse input program in strict mode")
+ flagEnable = flag.String("enable", "none", "enable only listed additional features")
+ flagDisable = flag.String("disable", "none", "enable all additional features except listed")
)
func main() {
+ flag.Usage = func() {
+ flag.PrintDefaults()
+ csource.PrintAvailableFeaturesFlags()
+ }
flag.Parse()
if *flagProg == "" {
- flag.PrintDefaults()
+ flag.Usage()
os.Exit(1)
}
+ features, err := csource.ParseFeaturesFlags(*flagEnable, *flagDisable, false)
+ if err != nil {
+ log.Fatalf("%v", err)
+ }
target, err := prog.GetTarget(*flagOS, *flagArch)
if err != nil {
fmt.Fprintf(os.Stderr, "%v", err)
@@ -63,23 +70,24 @@ func main() {
os.Exit(1)
}
opts := csource.Options{
- Threaded: *flagThreaded,
- Collide: *flagCollide,
- Repeat: *flagRepeat != 1,
- RepeatTimes: *flagRepeat,
- Procs: *flagProcs,
- Sandbox: *flagSandbox,
- Fault: *flagFaultCall >= 0,
- FaultCall: *flagFaultCall,
- FaultNth: *flagFaultNth,
- EnableTun: *flagEnableTun,
- UseTmpDir: *flagUseTmpDir,
- EnableCgroups: *flagCgroups,
- EnableNetdev: *flagNetdev,
- ResetNet: *flagResetNet,
- HandleSegv: *flagHandleSegv,
- Repro: false,
- Trace: *flagTrace,
+ Threaded: *flagThreaded,
+ Collide: *flagCollide,
+ Repeat: *flagRepeat != 1,
+ RepeatTimes: *flagRepeat,
+ Procs: *flagProcs,
+ Sandbox: *flagSandbox,
+ Fault: *flagFaultCall >= 0,
+ FaultCall: *flagFaultCall,
+ FaultNth: *flagFaultNth,
+ EnableTun: features["tun"].Enabled,
+ EnableNetDev: features["net_dev"].Enabled,
+ EnableNetReset: features["net_reset"].Enabled,
+ EnableCgroups: features["cgroups"].Enabled,
+ EnableBinfmtMisc: features["binfmt_misc"].Enabled,
+ UseTmpDir: *flagUseTmpDir,
+ HandleSegv: *flagHandleSegv,
+ Repro: false,
+ Trace: *flagTrace,
}
src, err := csource.Write(p, opts)
if err != nil {
diff --git a/tools/syz-stress/stress.go b/tools/syz-stress/stress.go
index c56936377..e287b4468 100644
--- a/tools/syz-stress/stress.go
+++ b/tools/syz-stress/stress.go
@@ -14,6 +14,7 @@ import (
"sync/atomic"
"time"
+ "github.com/google/syzkaller/pkg/csource"
"github.com/google/syzkaller/pkg/db"
"github.com/google/syzkaller/pkg/host"
"github.com/google/syzkaller/pkg/ipc"
@@ -32,7 +33,9 @@ var (
flagProcs = flag.Int("procs", 2*runtime.NumCPU(), "number of parallel processes")
flagLogProg = flag.Bool("logprog", false, "print programs before execution")
flagGenerate = flag.Bool("generate", true, "generate new programs, otherwise only mutate corpus")
- flagEnable = flag.String("enable", "", "comma-separated list of enabled syscalls")
+ flagSyscalls = flag.String("syscalls", "", "comma-separated list of enabled syscalls")
+ flagEnable = flag.String("enable", "none", "enable only listed additional features")
+ flagDisable = flag.String("disable", "none", "enable all additional features except listed")
statExec uint64
gate *ipc.Gate
@@ -41,7 +44,15 @@ var (
const programLength = 30
func main() {
+ flag.Usage = func() {
+ flag.PrintDefaults()
+ csource.PrintAvailableFeaturesFlags()
+ }
flag.Parse()
+ featuresFlags, err := csource.ParseFeaturesFlags(*flagEnable, *flagDisable, true)
+ if err != nil {
+ log.Fatalf("%v", err)
+ }
target, err := prog.GetTarget(*flagOS, *flagArch)
if err != nil {
log.Fatalf("%v", err)
@@ -60,7 +71,7 @@ func main() {
log.Fatalf("%v", err)
}
- calls := buildCallList(target, strings.Split(*flagEnable, ","))
+ calls := buildCallList(target, strings.Split(*flagSyscalls, ","))
prios := target.CalculatePriorities(corpus)
ct := target.BuildChoiceTable(prios, calls)
@@ -68,12 +79,21 @@ func main() {
if err != nil {
log.Fatalf("%v", err)
}
- if features[host.FeatureNetworkInjection].Enabled {
+ if featuresFlags["tun"].Enabled && features[host.FeatureNetworkInjection].Enabled {
config.Flags |= ipc.FlagEnableTun
}
- if features[host.FeatureNetworkDevices].Enabled {
+ if featuresFlags["net_dev"].Enabled && features[host.FeatureNetworkDevices].Enabled {
config.Flags |= ipc.FlagEnableNetDev
}
+ if featuresFlags["net_reset"].Enabled {
+ config.Flags |= ipc.FlagEnableNetReset
+ }
+ if featuresFlags["cgroups"].Enabled {
+ config.Flags |= ipc.FlagEnableCgroups
+ }
+ if featuresFlags["binfmt_misc"].Enabled {
+ config.Flags |= ipc.FlagEnableBinfmtMisc
+ }
gate = ipc.NewGate(2**flagProcs, nil)
for pid := 0; pid < *flagProcs; pid++ {
pid := pid