all: add optional close_fds feature to reproducers
Instead of always closing open fds (number 3 to 30) after each program,
add an options called EnableCloseFds. It can be passed to syz-execprog,
syz-prog2c and syz-stress via the -enable and -disable flags. Set the
default value to true. Also minimize C repros over it, except for when
repeat is enabled.
diff --git a/executor/common.h b/executor/common.h
index 5f33d3b..10e5b96 100644
--- a/executor/common.h
+++ b/executor/common.h
@@ -483,6 +483,9 @@
}
for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
sleep_ms(1);
+#if SYZ_HAVE_CLOSE_FDS
+ close_fds();
+#endif
#if SYZ_COLLIDE
if (!collide) {
collide = 1;
@@ -571,8 +574,8 @@
close(kOutPipeFd);
#endif
execute_one();
-#if SYZ_HAVE_RESET_TEST
- reset_test();
+#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED
+ close_fds();
#endif
doexit(0);
#endif
@@ -659,6 +662,9 @@
#endif
{
/*SYSCALLS*/
+#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT
+ close_fds();
+#endif
}
#endif
@@ -690,6 +696,10 @@
use_temporary_dir();
#endif
/*SANDBOX_FUNC*/
+#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT && !SYZ_SANDBOX_NONE && \
+ !SYZ_SANDBOX_SETUID && !SYZ_SANDBOX_NAMESPACE && !SYZ_SANDBOX_ANDROID_UNTRUSTED_APP
+ close_fds();
+#endif
#if SYZ_PROCS
}
}
diff --git a/executor/common_linux.h b/executor/common_linux.h
index b849555..0fd7a15 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -2612,12 +2612,20 @@
flush_tun();
#endif
}
+#endif
-#define SYZ_HAVE_RESET_TEST 1
-static void reset_test()
+#if SYZ_EXECUTOR || SYZ_ENABLE_CLOSE_FDS
+#define SYZ_HAVE_CLOSE_FDS 1
+static void close_fds()
{
+#if SYZ_EXECUTOR
+ if (!flag_enable_close_fds)
+ return;
+#endif
// Keeping a 9p transport pipe open will hang the proccess dead,
// so close all opened file descriptors.
+ // Also close all USB emulation descriptors to trigger exit from USB
+ // event loop to collect coverage.
int fd;
for (fd = 3; fd < 30; fd++)
close(fd);
diff --git a/executor/executor.cc b/executor/executor.cc
index f1f6ba2..bbbb2da 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -119,6 +119,7 @@
static bool flag_enable_net_reset;
static bool flag_enable_cgroups;
static bool flag_enable_binfmt_misc;
+static bool flag_enable_close_fds;
static bool flag_collect_cover;
static bool flag_dedup_cover;
@@ -454,6 +455,7 @@
flag_enable_net_reset = flags & (1 << 9);
flag_enable_cgroups = flags & (1 << 10);
flag_enable_binfmt_misc = flags & (1 << 11);
+ flag_enable_close_fds = flags & (1 << 12);
}
#if SYZ_EXECUTOR_USES_FORK_SERVER
@@ -732,6 +734,10 @@
}
}
+#if SYZ_HAVE_CLOSE_FDS
+ close_fds();
+#endif
+
if (flag_collide && !flag_inject_fault && !colliding && !collide) {
debug("enabling collider\n");
collide = colliding = true;
diff --git a/pkg/csource/common.go b/pkg/csource/common.go
index 204256d..d0c6340 100644
--- a/pkg/csource/common.go
+++ b/pkg/csource/common.go
@@ -89,6 +89,7 @@
"SYZ_ENABLE_NETDEV": opts.EnableNetDev,
"SYZ_RESET_NET_NAMESPACE": opts.EnableNetReset,
"SYZ_ENABLE_BINFMT_MISC": opts.EnableBinfmtMisc,
+ "SYZ_ENABLE_CLOSE_FDS": opts.EnableCloseFds,
"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 71a3810..4bd86bc 100644
--- a/pkg/csource/generated.go
+++ b/pkg/csource/generated.go
@@ -4319,10 +4319,16 @@
flush_tun();
#endif
}
+#endif
-#define SYZ_HAVE_RESET_TEST 1
-static void reset_test()
+#if SYZ_EXECUTOR || SYZ_ENABLE_CLOSE_FDS
+#define SYZ_HAVE_CLOSE_FDS 1
+static void close_fds()
{
+#if SYZ_EXECUTOR
+ if (!flag_enable_close_fds)
+ return;
+#endif
int fd;
for (fd = 3; fd < 30; fd++)
close(fd);
@@ -4614,6 +4620,9 @@
}
for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
sleep_ms(1);
+#if SYZ_HAVE_CLOSE_FDS
+ close_fds();
+#endif
#if SYZ_COLLIDE
if (!collide) {
collide = 1;
@@ -4698,8 +4707,8 @@
close(kOutPipeFd);
#endif
execute_one();
-#if SYZ_HAVE_RESET_TEST
- reset_test();
+#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED
+ close_fds();
#endif
doexit(0);
#endif
@@ -4771,6 +4780,9 @@
#endif
{
/*SYSCALLS*/
+#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT
+ close_fds();
+#endif
}
#endif
#if GOOS_akaros && SYZ_REPEAT
@@ -4800,6 +4812,10 @@
use_temporary_dir();
#endif
/*SANDBOX_FUNC*/
+#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT && !SYZ_SANDBOX_NONE && \
+ !SYZ_SANDBOX_SETUID && !SYZ_SANDBOX_NAMESPACE && !SYZ_SANDBOX_ANDROID_UNTRUSTED_APP
+ close_fds();
+#endif
#if SYZ_PROCS
}
}
diff --git a/pkg/csource/options.go b/pkg/csource/options.go
index d5b3961..0a95396 100644
--- a/pkg/csource/options.go
+++ b/pkg/csource/options.go
@@ -34,6 +34,7 @@
EnableNetReset bool `json:"resetnet,omitempty"`
EnableCgroups bool `json:"cgroups,omitempty"`
EnableBinfmtMisc bool `json:"binfmt_misc,omitempty"`
+ EnableCloseFds bool `json:"close_fds"`
UseTmpDir bool `json:"tmpdir,omitempty"`
HandleSegv bool `json:"segv,omitempty"`
@@ -117,6 +118,9 @@
if opts.EnableBinfmtMisc {
return fmt.Errorf("EnableBinfmtMisc is not supported on %v", OS)
}
+ if opts.EnableCloseFds {
+ return fmt.Errorf("EnableCloseFds is not supported on %v", OS)
+ }
if opts.Sandbox == sandboxNamespace ||
(opts.Sandbox == sandboxSetuid && !(OS == openbsd || OS == freebsd)) ||
opts.Sandbox == sandboxAndroidUntrustedApp {
@@ -140,6 +144,7 @@
EnableNetReset: true,
EnableCgroups: true,
EnableBinfmtMisc: true,
+ EnableCloseFds: true,
UseTmpDir: true,
HandleSegv: true,
Repro: true,
@@ -150,6 +155,7 @@
opts.EnableNetReset = false
opts.EnableCgroups = false
opts.EnableBinfmtMisc = false
+ opts.EnableCloseFds = false
}
if cfg.Sandbox == "" || cfg.Sandbox == "setuid" {
opts.EnableNetReset = false
@@ -170,6 +176,9 @@
func DeserializeOptions(data []byte) (Options, error) {
var opts Options
+ // Before EnableCloseFds was added, close_fds() was always called,
+ // so default to true.
+ opts.EnableCloseFds = true
if err := json.Unmarshal(data, &opts); err == nil {
return opts, nil
}
@@ -225,6 +234,7 @@
"net_reset": {"reset network namespace between programs", value},
"cgroups": {"setup cgroups for testing", value},
"binfmt_misc": {"setup binfmt_misc for testing", value},
+ "close_fds": {"close fds after each program", value},
}
}
diff --git a/pkg/csource/options_test.go b/pkg/csource/options_test.go
index 0240208..13afa84 100644
--- a/pkg/csource/options_test.go
+++ b/pkg/csource/options_test.go
@@ -44,6 +44,7 @@
EnableNetReset: true,
EnableCgroups: true,
EnableBinfmtMisc: false,
+ EnableCloseFds: true,
UseTmpDir: true,
HandleSegv: true,
Repro: true,
@@ -65,6 +66,7 @@
EnableNetReset: true,
EnableCgroups: true,
EnableBinfmtMisc: false,
+ EnableCloseFds: true,
UseTmpDir: true,
HandleSegv: true,
Repro: true,
@@ -81,6 +83,7 @@
EnableTun: true,
EnableCgroups: false,
EnableBinfmtMisc: false,
+ EnableCloseFds: true,
UseTmpDir: true,
HandleSegv: true,
Repro: false,
@@ -97,6 +100,7 @@
EnableTun: true,
EnableCgroups: false,
EnableBinfmtMisc: false,
+ EnableCloseFds: true,
UseTmpDir: true,
HandleSegv: true,
Repro: false,
@@ -113,6 +117,7 @@
EnableTun: true,
EnableCgroups: true,
EnableBinfmtMisc: false,
+ EnableCloseFds: true,
UseTmpDir: true,
HandleSegv: true,
Repro: false,
@@ -208,28 +213,31 @@
Features map[string]bool
}{
{"none", "none", true, map[string]bool{
- "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true,
+ "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true, "close_fds": true,
}},
{"none", "none", false, map[string]bool{
- "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false,
+ "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false, "close_fds": false,
}},
{"all", "none", true, map[string]bool{
- "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true,
+ "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true, "close_fds": true,
}},
{"", "none", true, map[string]bool{
- "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false,
+ "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false, "close_fds": false,
}},
{"none", "all", true, map[string]bool{
- "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false,
+ "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false, "close_fds": false,
}},
{"none", "", true, map[string]bool{
- "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true,
+ "tun": true, "net_dev": true, "net_reset": true, "cgroups": true, "binfmt_misc": true, "close_fds": true,
}},
{"tun,net_dev", "none", true, map[string]bool{
- "tun": true, "net_dev": true, "net_reset": false, "cgroups": false, "binfmt_misc": false,
+ "tun": true, "net_dev": true, "net_reset": false, "cgroups": false, "binfmt_misc": false, "close_fds": false,
}},
{"none", "cgroups,net_dev", true, map[string]bool{
- "tun": true, "net_dev": false, "net_reset": true, "cgroups": false, "binfmt_misc": true,
+ "tun": true, "net_dev": false, "net_reset": true, "cgroups": false, "binfmt_misc": true, "close_fds": true,
+ }},
+ {"close_fds", "none", true, map[string]bool{
+ "tun": false, "net_dev": false, "net_reset": false, "cgroups": false, "binfmt_misc": false, "close_fds": true,
}},
}
for i, test := range tests {
diff --git a/pkg/ipc/ipc.go b/pkg/ipc/ipc.go
index f3bc029..ab6c93a 100644
--- a/pkg/ipc/ipc.go
+++ b/pkg/ipc/ipc.go
@@ -38,6 +38,7 @@
FlagEnableNetReset // reset network namespace between programs
FlagEnableCgroups // setup cgroups for testing
FlagEnableBinfmtMisc // setup binfmt_misc for testing
+ FlagEnableCloseFds // close fds after each program
// 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 5db4116..af39016 100644
--- a/pkg/repro/repro.go
+++ b/pkg/repro/repro.go
@@ -809,6 +809,7 @@
opts.EnableNetReset = false
opts.EnableCgroups = false
opts.EnableBinfmtMisc = false
+ opts.EnableCloseFds = false
return true
},
func(opts *csource.Options) bool {
@@ -847,6 +848,15 @@
return true
},
func(opts *csource.Options) bool {
+ // We don't want to remove close_fds() call when repeat is enabled,
+ // since that can lead to deadlocks, see executor/common_linux.h.
+ if !opts.EnableCloseFds || opts.Repeat {
+ return false
+ }
+ opts.EnableCloseFds = false
+ return true
+ },
+ func(opts *csource.Options) bool {
if !opts.UseTmpDir || opts.Sandbox == "namespace" || opts.EnableCgroups {
return false
}
diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go
index d0ff157..b969380 100644
--- a/syz-fuzzer/fuzzer.go
+++ b/syz-fuzzer/fuzzer.go
@@ -202,6 +202,7 @@
config.Flags |= ipc.FlagEnableNetReset
config.Flags |= ipc.FlagEnableCgroups
config.Flags |= ipc.FlagEnableBinfmtMisc
+ config.Flags |= ipc.FlagEnableCloseFds
if *flagRunTest {
runTest(target, manager, *flagName, config.Executor)
diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go
index 07bae45..b2902ba 100644
--- a/tools/syz-execprog/execprog.go
+++ b/tools/syz-execprog/execprog.go
@@ -324,5 +324,8 @@
if featuresFlags["binfmt_misc"].Enabled {
config.Flags |= ipc.FlagEnableBinfmtMisc
}
+ if featuresFlags["close_fds"].Enabled {
+ config.Flags |= ipc.FlagEnableCloseFds
+ }
return config, execOpts
}
diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go
index d076ad2..86f703c 100644
--- a/tools/syz-prog2c/prog2c.go
+++ b/tools/syz-prog2c/prog2c.go
@@ -84,6 +84,7 @@
EnableNetReset: features["net_reset"].Enabled,
EnableCgroups: features["cgroups"].Enabled,
EnableBinfmtMisc: features["binfmt_misc"].Enabled,
+ EnableCloseFds: features["close_fds"].Enabled,
UseTmpDir: *flagUseTmpDir,
HandleSegv: *flagHandleSegv,
Repro: false,
diff --git a/tools/syz-stress/stress.go b/tools/syz-stress/stress.go
index e287b44..390a1fb 100644
--- a/tools/syz-stress/stress.go
+++ b/tools/syz-stress/stress.go
@@ -94,6 +94,9 @@
if featuresFlags["binfmt_misc"].Enabled {
config.Flags |= ipc.FlagEnableBinfmtMisc
}
+ if featuresFlags["close_fds"].Enabled {
+ config.Flags |= ipc.FlagEnableCloseFds
+ }
gate = ipc.NewGate(2**flagProcs, nil)
for pid := 0; pid < *flagProcs; pid++ {
pid := pid