From fd8caa5462e64f37cb9eebd75ffca1737dde447d Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Thu, 23 Sep 2021 16:15:41 +0000 Subject: all: replace collide mode by `async` call property Replace the currently existing straightforward approach to race triggering (that was almost entirely implemented inside syz-executor) with a more flexible one. The `async` call property instructs syz-executor not to block until the call has completed execution and proceed immediately to the next call. The decision on what calls to mark with `async` is made by syz-fuzzer. Ultimately this should let us implement more intelligent race provoking strategies as well as make more fine-grained reproducers. --- pkg/csource/common.go | 10 +++++----- pkg/csource/csource.go | 11 +++++++++++ pkg/csource/csource_test.go | 5 ++++- pkg/csource/generated.go | 14 ++------------ pkg/csource/options.go | 4 +--- pkg/csource/options_test.go | 10 +++++----- 6 files changed, 28 insertions(+), 26 deletions(-) (limited to 'pkg/csource') diff --git a/pkg/csource/common.go b/pkg/csource/common.go index a1525e24f..7e396931c 100644 --- a/pkg/csource/common.go +++ b/pkg/csource/common.go @@ -91,23 +91,23 @@ func defineList(p, mmapProg *prog.Prog, opts Options) (defines []string) { func commonDefines(p *prog.Prog, opts Options) map[string]bool { sysTarget := targets.Get(p.Target.OS, p.Target.Arch) - bitmasks, csums := prog.RequiredFeatures(p) + features := p.RequiredFeatures() return map[string]bool{ "GOOS_" + p.Target.OS: true, "GOARCH_" + p.Target.Arch: true, "HOSTGOOS_" + runtime.GOOS: true, - "SYZ_USE_BITMASKS": bitmasks, - "SYZ_USE_CHECKSUMS": csums, + "SYZ_USE_BITMASKS": features.Bitmasks, + "SYZ_USE_CHECKSUMS": features.Csums, "SYZ_SANDBOX_NONE": opts.Sandbox == sandboxNone, "SYZ_SANDBOX_SETUID": opts.Sandbox == sandboxSetuid, "SYZ_SANDBOX_NAMESPACE": opts.Sandbox == sandboxNamespace, "SYZ_SANDBOX_ANDROID": opts.Sandbox == sandboxAndroid, "SYZ_THREADED": opts.Threaded, - "SYZ_COLLIDE": opts.Collide, + "SYZ_ASYNC": features.Async, "SYZ_REPEAT": opts.Repeat, "SYZ_REPEAT_TIMES": opts.RepeatTimes > 1, "SYZ_MULTI_PROC": opts.Procs > 1, - "SYZ_FAULT": p.HasFaultInjection(), + "SYZ_FAULT": features.FaultInjection, "SYZ_LEAK": opts.Leak, "SYZ_NET_INJECTION": opts.NetInjection, "SYZ_NET_DEVICES": opts.NetDevices, diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index 68f961526..32e01ff1e 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -115,6 +115,17 @@ func (ctx *context) generateSource() ([]byte, error) { } } replacements["CALL_TIMEOUT_MS"] = timeoutExpr + if ctx.p.RequiredFeatures().Async { + conditions := []string{} + for idx, call := range ctx.p.Calls { + if !call.Props.Async { + continue + } + conditions = append(conditions, fmt.Sprintf("call == %v", idx)) + } + replacements["ASYNC_CONDITIONS"] = strings.Join(conditions, " || ") + } + result, err := createCommonHeader(ctx.p, mmapProg, replacements, ctx.opts) if err != nil { return nil, err diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go index aa242e876..885d75f67 100644 --- a/pkg/csource/csource_test.go +++ b/pkg/csource/csource_test.go @@ -70,10 +70,13 @@ func testTarget(t *testing.T, target *prog.Target, full bool) { p.Calls = append(p.Calls, minimized.Calls...) opts = allOptionsPermutations(target.OS) } + // Test fault injection and async call generation as well. if len(p.Calls) > 0 { - // Test fault injection code generation as well. p.Calls[0].Props.FailNth = 1 } + if len(p.Calls) > 1 { + p.Calls[1].Props.Async = true + } for opti, opts := range opts { if testing.Short() && opts.HandleSegv { // HandleSegv can radically increase compilation time/memory consumption on large programs. diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go index 728806967..851bf935a 100644 --- a/pkg/csource/generated.go +++ b/pkg/csource/generated.go @@ -10457,10 +10457,6 @@ static void loop(void) fprintf(stderr, "### start\n"); #endif int i, call, thread; -#if SYZ_COLLIDE - int collide = 0; -again: -#endif for (call = 0; call < /*{{{NUM_CALLS}}}*/; call++) { for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) { struct thread_t* th = &threads[thread]; @@ -10477,8 +10473,8 @@ again: th->call = call; __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); event_set(&th->ready); -#if SYZ_COLLIDE - if (collide && (call % 2) == 0) +#if SYZ_ASYNC + if (/*{{{ASYNC_CONDITIONS}}}*/) break; #endif event_timedwait(&th->done, /*{{{CALL_TIMEOUT_MS}}}*/); @@ -10490,12 +10486,6 @@ again: #if SYZ_HAVE_CLOSE_FDS close_fds(); #endif -#if SYZ_COLLIDE - if (!collide) { - collide = 1; - goto again; - } -#endif } #endif diff --git a/pkg/csource/options.go b/pkg/csource/options.go index 36490c8b8..3fc549282 100644 --- a/pkg/csource/options.go +++ b/pkg/csource/options.go @@ -19,7 +19,6 @@ import ( // Dashboard also provides serialized Options along with syzkaller reproducers. type Options struct { Threaded bool `json:"threaded,omitempty"` - Collide bool `json:"collide,omitempty"` Repeat bool `json:"repeat,omitempty"` RepeatTimes int `json:"repeat_times,omitempty"` // if non-0, repeat that many times Procs int `json:"procs"` @@ -55,6 +54,7 @@ type Options struct { // These are legacy options, they remain only for the sake of backward compatibility. type LegacyOptions struct { + Collide bool `json:"collide,omitempty"` Fault bool `json:"fault,omitempty"` FaultCall int `json:"fault_call,omitempty"` FaultNth int `json:"fault_nth,omitempty"` @@ -158,7 +158,6 @@ func (opts Options) checkLinuxOnly(OS string) error { func DefaultOpts(cfg *mgrconfig.Config) Options { opts := Options{ Threaded: true, - Collide: true, Repeat: true, Procs: cfg.Procs, Slowdown: cfg.Timeouts.Slowdown, @@ -322,7 +321,6 @@ func PrintAvailableFeaturesFlags() { // This is the main configuration used by executor, only for testing. var ExecutorOpts = Options{ Threaded: true, - Collide: true, Repeat: true, Procs: 2, Slowdown: 1, diff --git a/pkg/csource/options_test.go b/pkg/csource/options_test.go index ba31e4c95..5e971a9d1 100644 --- a/pkg/csource/options_test.go +++ b/pkg/csource/options_test.go @@ -34,7 +34,6 @@ func TestParseOptionsCanned(t *testing.T) { "netdev":true,"resetnet":true, "segv":true,"waitrepeat":true,"debug":true,"repro":true}`: { Threaded: true, - Collide: true, Repeat: true, Procs: 10, Slowdown: 1, @@ -49,6 +48,7 @@ func TestParseOptionsCanned(t *testing.T) { HandleSegv: true, Repro: true, LegacyOptions: LegacyOptions{ + Collide: true, Fault: true, FaultCall: 1, FaultNth: 2, @@ -59,7 +59,6 @@ func TestParseOptionsCanned(t *testing.T) { "netdev":true,"resetnet":true, "segv":true,"waitrepeat":true,"debug":true,"repro":true}`: { Threaded: true, - Collide: true, Repeat: true, Procs: 10, Slowdown: 1, @@ -74,6 +73,7 @@ func TestParseOptionsCanned(t *testing.T) { HandleSegv: true, Repro: true, LegacyOptions: LegacyOptions{ + Collide: true, Fault: true, FaultCall: 1, FaultNth: 2, @@ -81,7 +81,6 @@ func TestParseOptionsCanned(t *testing.T) { }, "{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, Slowdown: 1, @@ -94,6 +93,7 @@ func TestParseOptionsCanned(t *testing.T) { HandleSegv: true, Repro: false, LegacyOptions: LegacyOptions{ + Collide: true, Fault: false, FaultCall: -1, FaultNth: 0, @@ -101,7 +101,6 @@ func TestParseOptionsCanned(t *testing.T) { }, "{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, Slowdown: 1, @@ -114,6 +113,7 @@ func TestParseOptionsCanned(t *testing.T) { HandleSegv: true, Repro: false, LegacyOptions: LegacyOptions{ + Collide: true, Fault: false, FaultCall: -1, FaultNth: 0, @@ -121,7 +121,6 @@ func TestParseOptionsCanned(t *testing.T) { }, "{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, Slowdown: 1, @@ -134,6 +133,7 @@ func TestParseOptionsCanned(t *testing.T) { HandleSegv: true, Repro: false, LegacyOptions: LegacyOptions{ + Collide: true, Fault: false, FaultCall: -1, FaultNth: 0, -- cgit mrf-deployment