From dfd609eca1871f01757d6b04b19fc273c87c14e5 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Tue, 5 Feb 2019 16:19:34 +0100 Subject: 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. --- pkg/csource/common.go | 5 +- pkg/csource/generated.go | 188 ++++++++++++++++++++++++++++--------------- pkg/csource/options.go | 141 +++++++++++++++++++++++++-------- pkg/csource/options_test.go | 189 ++++++++++++++++++++++++++++---------------- pkg/ipc/ipc.go | 9 ++- pkg/repro/repro.go | 26 +++--- pkg/repro/repro_test.go | 24 +++--- pkg/runtest/run.go | 4 +- 8 files changed, 393 insertions(+), 193 deletions(-) (limited to 'pkg') 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 #include @@ -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 #include #include @@ -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 +#include +#include +#include + 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) -- cgit mrf-deployment