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.
This commit is contained in:
Andrey Konovalov 2019-04-05 18:44:53 +02:00 committed by Dmitry Vyukov
parent e619f52452
commit 5c51045d28
13 changed files with 94 additions and 16 deletions

View File

@ -483,6 +483,9 @@ again:
} }
for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
sleep_ms(1); sleep_ms(1);
#if SYZ_HAVE_CLOSE_FDS
close_fds();
#endif
#if SYZ_COLLIDE #if SYZ_COLLIDE
if (!collide) { if (!collide) {
collide = 1; collide = 1;
@ -571,8 +574,8 @@ static void loop(void)
close(kOutPipeFd); close(kOutPipeFd);
#endif #endif
execute_one(); execute_one();
#if SYZ_HAVE_RESET_TEST #if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED
reset_test(); close_fds();
#endif #endif
doexit(0); doexit(0);
#endif #endif
@ -659,6 +662,9 @@ void loop(void)
#endif #endif
{ {
/*SYSCALLS*/ /*SYSCALLS*/
#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT
close_fds();
#endif
} }
#endif #endif
@ -690,6 +696,10 @@ int main(void)
use_temporary_dir(); use_temporary_dir();
#endif #endif
/*SANDBOX_FUNC*/ /*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 #if SYZ_PROCS
} }
} }

View File

@ -2612,12 +2612,20 @@ static void setup_test()
flush_tun(); flush_tun();
#endif #endif
} }
#endif
#define SYZ_HAVE_RESET_TEST 1 #if SYZ_EXECUTOR || SYZ_ENABLE_CLOSE_FDS
static void reset_test() #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, // Keeping a 9p transport pipe open will hang the proccess dead,
// so close all opened file descriptors. // so close all opened file descriptors.
// Also close all USB emulation descriptors to trigger exit from USB
// event loop to collect coverage.
int fd; int fd;
for (fd = 3; fd < 30; fd++) for (fd = 3; fd < 30; fd++)
close(fd); close(fd);

View File

@ -119,6 +119,7 @@ static bool flag_enable_net_dev;
static bool flag_enable_net_reset; static bool flag_enable_net_reset;
static bool flag_enable_cgroups; static bool flag_enable_cgroups;
static bool flag_enable_binfmt_misc; static bool flag_enable_binfmt_misc;
static bool flag_enable_close_fds;
static bool flag_collect_cover; static bool flag_collect_cover;
static bool flag_dedup_cover; static bool flag_dedup_cover;
@ -454,6 +455,7 @@ void parse_env_flags(uint64 flags)
flag_enable_net_reset = flags & (1 << 9); flag_enable_net_reset = flags & (1 << 9);
flag_enable_cgroups = flags & (1 << 10); flag_enable_cgroups = flags & (1 << 10);
flag_enable_binfmt_misc = flags & (1 << 11); flag_enable_binfmt_misc = flags & (1 << 11);
flag_enable_close_fds = flags & (1 << 12);
} }
#if SYZ_EXECUTOR_USES_FORK_SERVER #if SYZ_EXECUTOR_USES_FORK_SERVER
@ -732,6 +734,10 @@ retry:
} }
} }
#if SYZ_HAVE_CLOSE_FDS
close_fds();
#endif
if (flag_collide && !flag_inject_fault && !colliding && !collide) { if (flag_collide && !flag_inject_fault && !colliding && !collide) {
debug("enabling collider\n"); debug("enabling collider\n");
collide = colliding = true; collide = colliding = true;

View File

@ -89,6 +89,7 @@ func defineList(p, mmapProg *prog.Prog, opts Options) (defines []string) {
"SYZ_ENABLE_NETDEV": opts.EnableNetDev, "SYZ_ENABLE_NETDEV": opts.EnableNetDev,
"SYZ_RESET_NET_NAMESPACE": opts.EnableNetReset, "SYZ_RESET_NET_NAMESPACE": opts.EnableNetReset,
"SYZ_ENABLE_BINFMT_MISC": opts.EnableBinfmtMisc, "SYZ_ENABLE_BINFMT_MISC": opts.EnableBinfmtMisc,
"SYZ_ENABLE_CLOSE_FDS": opts.EnableCloseFds,
"SYZ_USE_TMP_DIR": opts.UseTmpDir, "SYZ_USE_TMP_DIR": opts.UseTmpDir,
"SYZ_HANDLE_SEGV": opts.HandleSegv, "SYZ_HANDLE_SEGV": opts.HandleSegv,
"SYZ_REPRO": opts.Repro, "SYZ_REPRO": opts.Repro,

View File

@ -4319,10 +4319,16 @@ static void setup_test()
flush_tun(); flush_tun();
#endif #endif
} }
#endif
#define SYZ_HAVE_RESET_TEST 1 #if SYZ_EXECUTOR || SYZ_ENABLE_CLOSE_FDS
static void reset_test() #define SYZ_HAVE_CLOSE_FDS 1
static void close_fds()
{ {
#if SYZ_EXECUTOR
if (!flag_enable_close_fds)
return;
#endif
int fd; int fd;
for (fd = 3; fd < 30; fd++) for (fd = 3; fd < 30; fd++)
close(fd); close(fd);
@ -4614,6 +4620,9 @@ again:
} }
for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
sleep_ms(1); sleep_ms(1);
#if SYZ_HAVE_CLOSE_FDS
close_fds();
#endif
#if SYZ_COLLIDE #if SYZ_COLLIDE
if (!collide) { if (!collide) {
collide = 1; collide = 1;
@ -4698,8 +4707,8 @@ static void loop(void)
close(kOutPipeFd); close(kOutPipeFd);
#endif #endif
execute_one(); execute_one();
#if SYZ_HAVE_RESET_TEST #if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED
reset_test(); close_fds();
#endif #endif
doexit(0); doexit(0);
#endif #endif
@ -4771,6 +4780,9 @@ void loop(void)
#endif #endif
{ {
/*SYSCALLS*/ /*SYSCALLS*/
#if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT
close_fds();
#endif
} }
#endif #endif
#if GOOS_akaros && SYZ_REPEAT #if GOOS_akaros && SYZ_REPEAT
@ -4800,6 +4812,10 @@ int main(void)
use_temporary_dir(); use_temporary_dir();
#endif #endif
/*SANDBOX_FUNC*/ /*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 #if SYZ_PROCS
} }
} }

View File

@ -34,6 +34,7 @@ type Options struct {
EnableNetReset bool `json:"resetnet,omitempty"` EnableNetReset bool `json:"resetnet,omitempty"`
EnableCgroups bool `json:"cgroups,omitempty"` EnableCgroups bool `json:"cgroups,omitempty"`
EnableBinfmtMisc bool `json:"binfmt_misc,omitempty"` EnableBinfmtMisc bool `json:"binfmt_misc,omitempty"`
EnableCloseFds bool `json:"close_fds"`
UseTmpDir bool `json:"tmpdir,omitempty"` UseTmpDir bool `json:"tmpdir,omitempty"`
HandleSegv bool `json:"segv,omitempty"` HandleSegv bool `json:"segv,omitempty"`
@ -117,6 +118,9 @@ func (opts Options) checkLinuxOnly(OS string) error {
if opts.EnableBinfmtMisc { if opts.EnableBinfmtMisc {
return fmt.Errorf("EnableBinfmtMisc is not supported on %v", OS) 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 || if opts.Sandbox == sandboxNamespace ||
(opts.Sandbox == sandboxSetuid && !(OS == openbsd || OS == freebsd)) || (opts.Sandbox == sandboxSetuid && !(OS == openbsd || OS == freebsd)) ||
opts.Sandbox == sandboxAndroidUntrustedApp { opts.Sandbox == sandboxAndroidUntrustedApp {
@ -140,6 +144,7 @@ func DefaultOpts(cfg *mgrconfig.Config) Options {
EnableNetReset: true, EnableNetReset: true,
EnableCgroups: true, EnableCgroups: true,
EnableBinfmtMisc: true, EnableBinfmtMisc: true,
EnableCloseFds: true,
UseTmpDir: true, UseTmpDir: true,
HandleSegv: true, HandleSegv: true,
Repro: true, Repro: true,
@ -150,6 +155,7 @@ func DefaultOpts(cfg *mgrconfig.Config) Options {
opts.EnableNetReset = false opts.EnableNetReset = false
opts.EnableCgroups = false opts.EnableCgroups = false
opts.EnableBinfmtMisc = false opts.EnableBinfmtMisc = false
opts.EnableCloseFds = false
} }
if cfg.Sandbox == "" || cfg.Sandbox == "setuid" { if cfg.Sandbox == "" || cfg.Sandbox == "setuid" {
opts.EnableNetReset = false opts.EnableNetReset = false
@ -170,6 +176,9 @@ func (opts Options) Serialize() []byte {
func DeserializeOptions(data []byte) (Options, error) { func DeserializeOptions(data []byte) (Options, error) {
var opts Options 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 { if err := json.Unmarshal(data, &opts); err == nil {
return opts, nil return opts, nil
} }
@ -225,6 +234,7 @@ func defaultFeatures(value bool) Features {
"net_reset": {"reset network namespace between programs", value}, "net_reset": {"reset network namespace between programs", value},
"cgroups": {"setup cgroups for testing", value}, "cgroups": {"setup cgroups for testing", value},
"binfmt_misc": {"setup binfmt_misc for testing", value}, "binfmt_misc": {"setup binfmt_misc for testing", value},
"close_fds": {"close fds after each program", value},
} }
} }

View File

@ -44,6 +44,7 @@ func TestParseOptionsCanned(t *testing.T) {
EnableNetReset: true, EnableNetReset: true,
EnableCgroups: true, EnableCgroups: true,
EnableBinfmtMisc: false, EnableBinfmtMisc: false,
EnableCloseFds: true,
UseTmpDir: true, UseTmpDir: true,
HandleSegv: true, HandleSegv: true,
Repro: true, Repro: true,
@ -65,6 +66,7 @@ func TestParseOptionsCanned(t *testing.T) {
EnableNetReset: true, EnableNetReset: true,
EnableCgroups: true, EnableCgroups: true,
EnableBinfmtMisc: false, EnableBinfmtMisc: false,
EnableCloseFds: true,
UseTmpDir: true, UseTmpDir: true,
HandleSegv: true, HandleSegv: true,
Repro: true, Repro: true,
@ -81,6 +83,7 @@ func TestParseOptionsCanned(t *testing.T) {
EnableTun: true, EnableTun: true,
EnableCgroups: false, EnableCgroups: false,
EnableBinfmtMisc: false, EnableBinfmtMisc: false,
EnableCloseFds: true,
UseTmpDir: true, UseTmpDir: true,
HandleSegv: true, HandleSegv: true,
Repro: false, Repro: false,
@ -97,6 +100,7 @@ func TestParseOptionsCanned(t *testing.T) {
EnableTun: true, EnableTun: true,
EnableCgroups: false, EnableCgroups: false,
EnableBinfmtMisc: false, EnableBinfmtMisc: false,
EnableCloseFds: true,
UseTmpDir: true, UseTmpDir: true,
HandleSegv: true, HandleSegv: true,
Repro: false, Repro: false,
@ -113,6 +117,7 @@ func TestParseOptionsCanned(t *testing.T) {
EnableTun: true, EnableTun: true,
EnableCgroups: true, EnableCgroups: true,
EnableBinfmtMisc: false, EnableBinfmtMisc: false,
EnableCloseFds: true,
UseTmpDir: true, UseTmpDir: true,
HandleSegv: true, HandleSegv: true,
Repro: false, Repro: false,
@ -208,28 +213,31 @@ func TestParseFeaturesFlags(t *testing.T) {
Features map[string]bool Features map[string]bool
}{ }{
{"none", "none", true, 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{ {"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{ {"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{ {"", "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{ {"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{ {"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,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{ {"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 { for i, test := range tests {

View File

@ -38,6 +38,7 @@ const (
FlagEnableNetReset // reset network namespace between programs FlagEnableNetReset // reset network namespace between programs
FlagEnableCgroups // setup cgroups for testing FlagEnableCgroups // setup cgroups for testing
FlagEnableBinfmtMisc // setup binfmt_misc for testing FlagEnableBinfmtMisc // setup binfmt_misc for testing
FlagEnableCloseFds // close fds after each program
// Executor does not know about these: // Executor does not know about these:
FlagUseShmem // use shared memory instead of pipes for communication FlagUseShmem // use shared memory instead of pipes for communication
FlagUseForkServer // use extended protocol with handshake FlagUseForkServer // use extended protocol with handshake

View File

@ -809,6 +809,7 @@ var cSimplifies = append(progSimplifies, []Simplify{
opts.EnableNetReset = false opts.EnableNetReset = false
opts.EnableCgroups = false opts.EnableCgroups = false
opts.EnableBinfmtMisc = false opts.EnableBinfmtMisc = false
opts.EnableCloseFds = false
return true return true
}, },
func(opts *csource.Options) bool { func(opts *csource.Options) bool {
@ -846,6 +847,15 @@ var cSimplifies = append(progSimplifies, []Simplify{
opts.EnableBinfmtMisc = false opts.EnableBinfmtMisc = false
return true 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 { func(opts *csource.Options) bool {
if !opts.UseTmpDir || opts.Sandbox == "namespace" || opts.EnableCgroups { if !opts.UseTmpDir || opts.Sandbox == "namespace" || opts.EnableCgroups {
return false return false

View File

@ -202,6 +202,7 @@ func main() {
config.Flags |= ipc.FlagEnableNetReset config.Flags |= ipc.FlagEnableNetReset
config.Flags |= ipc.FlagEnableCgroups config.Flags |= ipc.FlagEnableCgroups
config.Flags |= ipc.FlagEnableBinfmtMisc config.Flags |= ipc.FlagEnableBinfmtMisc
config.Flags |= ipc.FlagEnableCloseFds
if *flagRunTest { if *flagRunTest {
runTest(target, manager, *flagName, config.Executor) runTest(target, manager, *flagName, config.Executor)

View File

@ -324,5 +324,8 @@ func createConfig(target *prog.Target, entries []*prog.LogEntry,
if featuresFlags["binfmt_misc"].Enabled { if featuresFlags["binfmt_misc"].Enabled {
config.Flags |= ipc.FlagEnableBinfmtMisc config.Flags |= ipc.FlagEnableBinfmtMisc
} }
if featuresFlags["close_fds"].Enabled {
config.Flags |= ipc.FlagEnableCloseFds
}
return config, execOpts return config, execOpts
} }

View File

@ -84,6 +84,7 @@ func main() {
EnableNetReset: features["net_reset"].Enabled, EnableNetReset: features["net_reset"].Enabled,
EnableCgroups: features["cgroups"].Enabled, EnableCgroups: features["cgroups"].Enabled,
EnableBinfmtMisc: features["binfmt_misc"].Enabled, EnableBinfmtMisc: features["binfmt_misc"].Enabled,
EnableCloseFds: features["close_fds"].Enabled,
UseTmpDir: *flagUseTmpDir, UseTmpDir: *flagUseTmpDir,
HandleSegv: *flagHandleSegv, HandleSegv: *flagHandleSegv,
Repro: false, Repro: false,

View File

@ -94,6 +94,9 @@ func main() {
if featuresFlags["binfmt_misc"].Enabled { if featuresFlags["binfmt_misc"].Enabled {
config.Flags |= ipc.FlagEnableBinfmtMisc config.Flags |= ipc.FlagEnableBinfmtMisc
} }
if featuresFlags["close_fds"].Enabled {
config.Flags |= ipc.FlagEnableCloseFds
}
gate = ipc.NewGate(2**flagProcs, nil) gate = ipc.NewGate(2**flagProcs, nil)
for pid := 0; pid < *flagProcs; pid++ { for pid := 0; pid < *flagProcs; pid++ {
pid := pid pid := pid