aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/csource
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-03-22 13:24:02 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-03-25 12:46:05 +0200
commit2675f920652cc9218b4b3dc513c76b0546a5a5ae (patch)
tree8ae9084acf230839d4b7f2eeef2ba4549ee8d35d /pkg/csource
parent2e9d905410db5615d2e7d3418979d79249ac74f6 (diff)
sys/linux: add cgroup descriptions
Diffstat (limited to 'pkg/csource')
-rw-r--r--pkg/csource/akaros_common.go5
-rw-r--r--pkg/csource/common.go3
-rw-r--r--pkg/csource/csource.go6
-rw-r--r--pkg/csource/csource_test.go1
-rw-r--r--pkg/csource/freebsd_common.go5
-rw-r--r--pkg/csource/linux_common.go290
-rw-r--r--pkg/csource/netbsd_common.go5
-rw-r--r--pkg/csource/options.go52
-rw-r--r--pkg/csource/options_test.go85
9 files changed, 360 insertions, 92 deletions
diff --git a/pkg/csource/akaros_common.go b/pkg/csource/akaros_common.go
index 36b674520..d0009cac5 100644
--- a/pkg/csource/akaros_common.go
+++ b/pkg/csource/akaros_common.go
@@ -78,6 +78,11 @@ typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
+#ifdef SYZ_EXECUTOR
+const int kInPipeFd = 250;
+const int kOutPipeFd = 251;
+#endif
+
#if defined(__GNUC__)
#define SYSCALLAPI
#define NORETURN __attribute__((noreturn))
diff --git a/pkg/csource/common.go b/pkg/csource/common.go
index f77df3459..27caac40d 100644
--- a/pkg/csource/common.go
+++ b/pkg/csource/common.go
@@ -89,6 +89,9 @@ func defineList(p *prog.Prog, opts Options) ([]string, error) {
if opts.EnableTun {
defines = append(defines, "SYZ_TUN_ENABLE")
}
+ if opts.EnableCgroups {
+ defines = append(defines, "SYZ_ENABLE_CGROUPS")
+ }
if opts.UseTmpDir {
defines = append(defines, "SYZ_USE_TMP_DIR")
}
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index 759daa30f..6d20aed50 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -63,8 +63,8 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
}
ctx.printf("};\n")
}
- if opts.Procs > 1 {
- ctx.printf("uint64_t procid;\n")
+ if opts.Procs > 1 || opts.EnableCgroups {
+ ctx.printf("unsigned long long procid;\n")
}
if !opts.Repeat {
@@ -93,7 +93,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
}
ctx.print("\treturn 0;\n}\n")
} else {
- ctx.generateTestFunc(calls, len(vars) != 0, "test")
+ ctx.generateTestFunc(calls, len(vars) != 0, "execute_one")
if opts.Procs <= 1 {
ctx.print("int main()\n{\n")
for _, c := range mmapCalls {
diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go
index fa5eee58a..c90a5ff0a 100644
--- a/pkg/csource/csource_test.go
+++ b/pkg/csource/csource_test.go
@@ -89,6 +89,7 @@ func TestGenerateOptions(t *testing.T) {
permutations = allPermutations
}
for i, opts := range permutations {
+ opts := opts
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
target, rs, iters := initTest(t)
t.Logf("opts: %+v", opts)
diff --git a/pkg/csource/freebsd_common.go b/pkg/csource/freebsd_common.go
index b6aff4706..ef177b325 100644
--- a/pkg/csource/freebsd_common.go
+++ b/pkg/csource/freebsd_common.go
@@ -69,6 +69,11 @@ typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
+#ifdef SYZ_EXECUTOR
+const int kInPipeFd = 250;
+const int kOutPipeFd = 251;
+#endif
+
#if defined(__GNUC__)
#define SYSCALLAPI
#define NORETURN __attribute__((noreturn))
diff --git a/pkg/csource/linux_common.go b/pkg/csource/linux_common.go
index 12a2c1cac..8ddced733 100644
--- a/pkg/csource/linux_common.go
+++ b/pkg/csource/linux_common.go
@@ -44,15 +44,20 @@ var commonHeaderLinux = `
#include <sys/time.h>
#include <sys/wait.h>
#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) || defined(SYZ_SANDBOX_NAMESPACE) || \
+ defined(SYZ_ENABLE_CGROUPS)
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_SETUID)
#include <grp.h>
#endif
#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NAMESPACE)
-#include <fcntl.h>
#include <linux/capability.h>
#include <sys/mman.h>
#include <sys/mount.h>
-#include <sys/stat.h>
#endif
#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE)
#include <arpa/inet.h>
@@ -121,11 +126,15 @@ var commonHeaderLinux = `
#include <unistd.h>
#endif
#if defined(SYZ_EXECUTOR) || defined(__NR_syz_genetlink_get_family_id)
+#include <errno.h>
#include <linux/genetlink.h>
#include <linux/netlink.h>
#include <sys/socket.h>
#include <sys/types.h>
#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+#include <sys/mount.h>
+#endif
#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
defined(SYZ_USE_TMP_DIR) || defined(SYZ_HANDLE_SEGV) || defined(SYZ_TUN_ENABLE) || \
@@ -176,6 +185,11 @@ typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
+#ifdef SYZ_EXECUTOR
+const int kInPipeFd = 250;
+const int kOutPipeFd = 251;
+#endif
+
#if defined(__GNUC__)
#define SYSCALLAPI
#define NORETURN __attribute__((noreturn))
@@ -1857,6 +1871,74 @@ static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin
#endif
#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) || defined(SYZ_SANDBOX_NAMESPACE) || \
+ defined(SYZ_ENABLE_CGROUPS)
+static bool write_file(const char* file, const char* what, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, what);
+ vsnprintf(buf, sizeof(buf), what, args);
+ va_end(args);
+ buf[sizeof(buf) - 1] = 0;
+ int len = strlen(buf);
+
+ int fd = open(file, O_WRONLY | O_CLOEXEC);
+ if (fd == -1)
+ return false;
+ if (write(fd, buf, len) != len) {
+ int err = errno;
+ close(fd);
+ errno = err;
+ return false;
+ }
+ close(fd);
+ return true;
+}
+#endif
+
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+static void setup_cgroups()
+{
+ if (mkdir("/syzcgroup", 0777)) {
+ debug("mkdir(/syzcgroup) failed: %d\n", errno);
+ }
+ if (mkdir("/syzcgroup/unified", 0777)) {
+ debug("mkdir(/syzcgroup/unified) failed: %d\n", errno);
+ }
+ if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
+ debug("mount(cgroup2) failed: %d\n", errno);
+ }
+ if (chmod("/syzcgroup/unified", 0777)) {
+ debug("chmod(/syzcgroup/unified) failed: %d\n", errno);
+ }
+ if (!write_file("/syzcgroup/unified/cgroup.subtree_control", "+cpu +memory +io +pids +rdma")) {
+ debug("write(cgroup.subtree_control) failed: %d\n", errno);
+ }
+ if (mkdir("/syzcgroup/cpu", 0777)) {
+ debug("mkdir(/syzcgroup/cpu) failed: %d\n", errno);
+ }
+ if (mount("none", "/syzcgroup/cpu", "cgroup", 0, "cpuset,cpuacct,perf_event,hugetlb")) {
+ debug("mount(cgroup cpu) failed: %d\n", errno);
+ }
+ if (!write_file("/syzcgroup/cpu/cgroup.clone_children", "1")) {
+ debug("write(/syzcgroup/cpu/cgroup.clone_children) failed: %d\n", errno);
+ }
+ if (chmod("/syzcgroup/cpu", 0777)) {
+ debug("chmod(/syzcgroup/cpu) failed: %d\n", errno);
+ }
+ if (mkdir("/syzcgroup/net", 0777)) {
+ debug("mkdir(/syzcgroup/net) failed: %d\n", errno);
+ }
+ if (mount("none", "/syzcgroup/net", "cgroup", 0, "net_cls,net_prio,devices,freezer")) {
+ debug("mount(cgroup net) failed: %d\n", errno);
+ }
+ if (chmod("/syzcgroup/net", 0777)) {
+ debug("chmod(/syzcgroup/net) failed: %d\n", errno);
+ }
+}
+#endif
+
#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE)
static void loop();
@@ -1921,6 +2003,9 @@ static int do_sandbox_none(void)
if (pid)
return pid;
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+ setup_cgroups();
+#endif
sandbox_common();
if (unshare(CLONE_NEWNET)) {
debug("unshare(CLONE_NEWNET): %d\n", errno);
@@ -1946,6 +2031,9 @@ static int do_sandbox_setuid(void)
if (pid)
return pid;
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+ setup_cgroups();
+#endif
sandbox_common();
if (unshare(CLONE_NEWNET))
fail("unshare(CLONE_NEWNET)");
@@ -1969,29 +2057,6 @@ static int do_sandbox_setuid(void)
}
#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NAMESPACE) || defined(SYZ_FAULT_INJECTION)
-static bool write_file(const char* file, const char* what, ...)
-{
- char buf[1024];
- va_list args;
- va_start(args, what);
- vsnprintf(buf, sizeof(buf), what, args);
- va_end(args);
- buf[sizeof(buf) - 1] = 0;
- int len = strlen(buf);
-
- int fd = open(file, O_WRONLY | O_CLOEXEC);
- if (fd == -1)
- return false;
- if (write(fd, buf, len) != len) {
- close(fd);
- return false;
- }
- close(fd);
- return true;
-}
-#endif
-
#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NAMESPACE)
static int real_uid;
static int real_gid;
@@ -2038,6 +2103,29 @@ static int namespace_sandbox_proc(void* arg)
if (mount("/sys/fs/selinux", selinux_path, NULL, mount_flags, NULL) && errno != ENOENT)
fail("mount(/sys/fs/selinux) failed");
}
+ if (mkdir("./syz-tmp/newroot/sys", 0700))
+ fail("mkdir failed");
+ if (mount(NULL, "./syz-tmp/newroot/sys", "sysfs", 0, NULL))
+ fail("mount(sysfs) failed");
+#if defined(SYZ_EXECUTOR) || defined(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, mount_flags, NULL)) {
+ debug("mount(cgroup2, MS_BIND) failed: %d\n", errno);
+ }
+ if (mount("/syzcgroup/cpu", "./syz-tmp/newroot/syzcgroup/cpu", NULL, mount_flags, NULL)) {
+ debug("mount(cgroup/cpu, MS_BIND) failed: %d\n", errno);
+ }
+ if (mount("/syzcgroup/net", "./syz-tmp/newroot/syzcgroup/net", NULL, mount_flags, NULL)) {
+ debug("mount(cgroup/net, MS_BIND) failed: %d\n", errno);
+ }
+#endif
if (mkdir("./syz-tmp/pivot", 0777))
fail("mkdir failed");
if (syscall(SYS_pivot_root, "./syz-tmp", "./syz-tmp/pivot")) {
@@ -2076,6 +2164,9 @@ static int do_sandbox_namespace(void)
{
int pid;
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+ setup_cgroups();
+#endif
real_uid = getuid();
real_gid = getgid();
mprotect(sandbox_stack, 4096, PROT_NONE);
@@ -2577,58 +2668,163 @@ static int fault_injected(int fail_fd)
}
#endif
-#if defined(SYZ_REPEAT)
-static void test();
+#if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT)
+static void execute_one();
+extern unsigned long long procid;
-#if defined(SYZ_WAIT_REPEAT)
-void loop()
+#if defined(SYZ_EXECUTOR)
+void reply_handshake();
+void receive_execute(bool need_prog);
+void reply_execute(int status);
+extern uint32* output_data;
+extern uint32* output_pos;
+#endif
+
+#if defined(SYZ_EXECUTOR) || defined(SYZ_WAIT_REPEAT)
+static void loop()
{
- int iter;
-#if defined(SYZ_RESET_NET_NAMESPACE)
+#if defined(SYZ_EXECUTOR)
+ reply_handshake();
+#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_RESET_NET_NAMESPACE)
checkpoint_net_namespace();
#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+ char cgroupdir[64];
+ snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
+ char cgroupdir_cpu[64];
+ snprintf(cgroupdir_cpu, sizeof(cgroupdir_cpu), "/syzcgroup/cpu/syz%llu", procid);
+ char cgroupdir_net[64];
+ snprintf(cgroupdir_net, sizeof(cgroupdir_net), "/syzcgroup/net/syz%llu", procid);
+#endif
+ int iter;
for (iter = 0;; iter++) {
-#ifdef SYZ_USE_TMP_DIR
- char cwdbuf[256];
+#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
+ char cwdbuf[32];
sprintf(cwdbuf, "./%d", iter);
if (mkdir(cwdbuf, 0777))
fail("failed to mkdir");
#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+ if (mkdir(cgroupdir, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
+ }
+ if (mkdir(cgroupdir_cpu, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir_cpu, errno);
+ }
+ if (mkdir(cgroupdir_net, 0777)) {
+ debug("mkdir(%s) failed: %d\n", cgroupdir_net, errno);
+ }
+#endif
+#if defined(SYZ_EXECUTOR)
+ receive_execute(false);
+#endif
int pid = fork();
if (pid < 0)
- fail("loop fork failed");
+ fail("clone failed");
if (pid == 0) {
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setpgrp();
-#ifdef SYZ_USE_TMP_DIR
+#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
if (chdir(cwdbuf))
fail("failed to chdir");
#endif
-#ifdef SYZ_TUN_ENABLE
+#if defined(SYZ_EXECUTOR)
+ close(kInPipeFd);
+ close(kOutPipeFd);
+#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+ if (symlink(cgroupdir, "./cgroup")) {
+ debug("symlink(%s, ./cgroup) failed: %d\n", cgroupdir, errno);
+ }
+ if (symlink(cgroupdir_cpu, "./cgroup.cpu")) {
+ debug("symlink(%s, ./cgroup.cpu) failed: %d\n", cgroupdir_cpu, errno);
+ }
+ if (symlink(cgroupdir_net, "./cgroup.net")) {
+ debug("symlink(%s, ./cgroup.net) failed: %d\n", cgroupdir_net, errno);
+ }
+ int pid = getpid();
+ if (!write_file("./cgroup/cgroup.procs", "%d", pid)) {
+ debug("write(./cgroup/cgroup.procs) failed: %d\n", errno);
+ }
+ if (!write_file("./cgroup.cpu/cgroup.procs", "%d", pid)) {
+ debug("write(./cgroup.cpu/cgroup.procs) failed: %d\n", errno);
+ }
+ if (!write_file("./cgroup.net/cgroup.procs", "%d", pid)) {
+ debug("write(./cgroup.net/cgroup.procs) failed: %d\n", errno);
+ }
+#endif
+#if defined(SYZ_EXECUTOR)
+ if (flag_enable_tun) {
+ flush_tun();
+ }
+ output_pos = output_data;
+#elif defined(SYZ_TUN_ENABLE)
flush_tun();
#endif
- test();
+ execute_one();
+ debug("worker exiting\n");
doexit(0);
}
+ debug("spawned worker pid %d\n", pid);
+
int status = 0;
uint64 start = current_time_ms();
+#if defined(SYZ_EXECUTOR)
+ uint64 last_executed = start;
+ uint32 executed_calls = __atomic_load_n(output_data, __ATOMIC_RELAXED);
+#endif
for (;;) {
int res = waitpid(-1, &status, __WALL | WNOHANG);
- if (res == pid)
+ if (res == pid) {
+ debug("waitpid(%d)=%d\n", pid, res);
break;
+ }
usleep(1000);
- if (current_time_ms() - start > 5 * 1000) {
- kill(-pid, SIGKILL);
- kill(pid, SIGKILL);
- while (waitpid(-1, &status, __WALL) != pid) {
- }
- break;
+#if defined(SYZ_EXECUTOR)
+ uint64 now = current_time_ms();
+ uint32 now_executed = __atomic_load_n(output_data, __ATOMIC_RELAXED);
+ if (executed_calls != now_executed) {
+ executed_calls = now_executed;
+ last_executed = now;
+ }
+ if ((now - start < 3 * 1000) && (now - last_executed < 500))
+ continue;
+#else
+ if (current_time_ms() - start < 3 * 1000)
+ continue;
+#endif
+ debug("waitpid(%d)=%d\n", pid, res);
+ debug("killing\n");
+ kill(-pid, SIGKILL);
+ kill(pid, SIGKILL);
+ while (waitpid(-1, &status, __WALL) != pid) {
}
+ break;
}
-#ifdef SYZ_USE_TMP_DIR
+#if defined(SYZ_EXECUTOR)
+ status = WEXITSTATUS(status);
+ if (status == kFailStatus)
+ fail("child failed");
+ if (status == kErrorStatus)
+ error("child errored");
+ reply_execute(0);
+#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
remove_dir(cwdbuf);
#endif
-#if defined(SYZ_RESET_NET_NAMESPACE)
+#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
+ if (rmdir(cgroupdir)) {
+ debug("rmdir(%s) failed: %d\n", cgroupdir, errno);
+ }
+ if (rmdir(cgroupdir_cpu)) {
+ debug("rmdir(%s) failed: %d\n", cgroupdir_cpu, errno);
+ }
+ if (rmdir(cgroupdir_net)) {
+ debug("rmdir(%s) failed: %d\n", cgroupdir_net, errno);
+ }
+#endif
+#if defined(SYZ_EXECUTOR) || defined(SYZ_RESET_NET_NAMESPACE)
reset_net_namespace();
#endif
}
@@ -2637,7 +2833,7 @@ void loop()
void loop()
{
while (1) {
- test();
+ execute_one();
}
}
#endif
diff --git a/pkg/csource/netbsd_common.go b/pkg/csource/netbsd_common.go
index 1a7e3ee6e..55e424f3e 100644
--- a/pkg/csource/netbsd_common.go
+++ b/pkg/csource/netbsd_common.go
@@ -69,6 +69,11 @@ typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
+#ifdef SYZ_EXECUTOR
+const int kInPipeFd = 250;
+const int kOutPipeFd = 251;
+#endif
+
#if defined(__GNUC__)
#define SYSCALLAPI
#define NORETURN __attribute__((noreturn))
diff --git a/pkg/csource/options.go b/pkg/csource/options.go
index 6d5f18fd5..d6fdf4739 100644
--- a/pkg/csource/options.go
+++ b/pkg/csource/options.go
@@ -23,11 +23,12 @@ type Options struct {
FaultNth int
// These options allow for a more fine-tuned control over the generated C code.
- EnableTun bool
- UseTmpDir bool
- HandleSegv bool
- WaitRepeat bool
- Debug bool
+ EnableTun bool
+ UseTmpDir bool
+ EnableCgroups bool
+ HandleSegv bool
+ WaitRepeat bool
+ Debug bool
// Generate code for use with repro package to prints log messages,
// which allows to distinguish between a hang and an absent crash.
@@ -55,6 +56,15 @@ func (opts Options) Check() error {
// which will fail if procs>1 and on second run of the program.
return errors.New("Sandbox=namespace without UseTmpDir")
}
+ if opts.EnableTun && opts.Sandbox == "" {
+ return errors.New("EnableTun without sandbox")
+ }
+ if opts.EnableCgroups && opts.Sandbox == "" {
+ return errors.New("EnableCgroups without sandbox")
+ }
+ if opts.EnableCgroups && !opts.UseTmpDir {
+ return errors.New("EnableCgroups without UseTmpDir")
+ }
return nil
}
@@ -72,14 +82,30 @@ func DeserializeOptions(data []byte) (Options, error) {
&opts.Threaded, &opts.Collide, &opts.Repeat, &opts.Procs, &opts.Sandbox,
&opts.Fault, &opts.FaultCall, &opts.FaultNth, &opts.EnableTun, &opts.UseTmpDir,
&opts.HandleSegv, &opts.WaitRepeat, &opts.Debug, &opts.Repro)
- if err != nil {
- return opts, fmt.Errorf("failed to parse repro options: %v", err)
- }
- if want := 14; n != want {
- return opts, fmt.Errorf("failed to parse repro options: got %v fields, want %v", n, want)
+ if err == nil {
+ if want := 14; n != want {
+ return opts, fmt.Errorf("failed to parse repro options: got %v fields, want %v", n, want)
+ }
+ if opts.Sandbox == "empty" {
+ opts.Sandbox = ""
+ }
+ return opts, nil
}
- if opts.Sandbox == "empty" {
- opts.Sandbox = ""
+ n, err = fmt.Sscanf(string(data),
+ "{Threaded:%t Collide:%t Repeat:%t Procs:%d Sandbox:%s"+
+ " Fault:%t FaultCall:%d FaultNth:%d EnableTun:%t UseTmpDir:%t"+
+ " EnableCgroups:%t HandleSegv:%t WaitRepeat:%t Debug:%t Repro:%t}",
+ &opts.Threaded, &opts.Collide, &opts.Repeat, &opts.Procs, &opts.Sandbox,
+ &opts.Fault, &opts.FaultCall, &opts.FaultNth, &opts.EnableTun, &opts.UseTmpDir,
+ &opts.EnableCgroups, &opts.HandleSegv, &opts.WaitRepeat, &opts.Debug, &opts.Repro)
+ if err == nil {
+ if want := 15; n != want {
+ return opts, fmt.Errorf("failed to parse repro options: got %v fields, want %v", n, want)
+ }
+ if opts.Sandbox == "empty" {
+ opts.Sandbox = ""
+ }
+ return opts, nil
}
- return opts, nil
+ return opts, err
}
diff --git a/pkg/csource/options_test.go b/pkg/csource/options_test.go
index f3f42a6fc..890bac75f 100644
--- a/pkg/csource/options_test.go
+++ b/pkg/csource/options_test.go
@@ -29,36 +29,55 @@ func TestParseOptionsCanned(t *testing.T) {
// so we need to be able to parse old formats.
canned := map[string]Options{
"{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}": Options{
- 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,
+ 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 HandleSegv:true WaitRepeat:true Debug:false Repro:false}": Options{
- 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,
+ 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 WaitRepeat:true Debug:false Repro:false}": Options{
+ 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,
},
}
for data, want := range canned {
@@ -76,7 +95,15 @@ func allOptionsSingle() []Options {
var opts []Options
fields := reflect.TypeOf(Options{}).NumField()
for i := 0; i < fields; i++ {
- opts = append(opts, enumerateField(Options{}, i)...)
+ // Because of constraints on options, we need some defaults
+ // (e.g. no collide without threaded).
+ opt := Options{
+ Threaded: true,
+ Repeat: true,
+ Sandbox: "none",
+ UseTmpDir: true,
+ }
+ opts = append(opts, enumerateField(opt, i)...)
}
return opts
}