From 65a2d5fb58431828105bc0be91acb631c8d1097d Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 5 Jul 2017 16:22:53 +0200 Subject: pkg/repro: try extracting C repro before simplifying options Sometimes C reproducers don't work after the generic prog options were simplified. This change makes syzkaller to try extracting a C repro before simplifying prog options and after each simplification step. This gives us more chance to generate a C reproducer. --- pkg/repro/repro.go | 271 +++++++++++++++++++++++++++-------------------------- 1 file changed, 139 insertions(+), 132 deletions(-) (limited to 'pkg') diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go index 128ad7c2f..2fbd42e14 100644 --- a/pkg/repro/repro.go +++ b/pkg/repro/repro.go @@ -140,6 +140,9 @@ func Run(crashLog []byte, cfg *mgrconfig.Config, vmPool *vm.Pool, vmIndexes []in }() res, err := ctx.repro(entries, crashStart) + if err != nil { + return nil, err + } if res != nil { ctx.reproLog(3, "repro crashed as:\n%s", string(ctx.report)) res.Stats = ctx.stats @@ -171,37 +174,41 @@ func (ctx *context) repro(entries []*prog.LogEntry, crashStart int) (*Result, er res, err := ctx.extractProg(entries) if err != nil { - return res, err + return nil, err } if res == nil { return nil, nil } - + defer func() { + res.Opts.Repro = false + }() res, err = ctx.minimizeProg(res) if err != nil { - return res, err - } - - res, err = ctx.simplifyProg(res) - if err != nil { - return res, err + return nil, err } + // Try extracting C repro without simplifying options first. res, err = ctx.extractC(res) if err != nil { - return res, err + return nil, err } + + // Simplify options and try extracting C repro. if !res.CRepro { - res.Opts.Repro = false - return res, nil + res, err = ctx.simplifyProg(res) + if err != nil { + return nil, err + } } - res, err = ctx.simplifyC(res) - if err != nil { - return res, err + // Simplify C related options. + if res.CRepro { + res, err = ctx.simplifyC(res) + if err != nil { + return nil, err + } } - res.Opts.Repro = false return res, nil } @@ -237,7 +244,7 @@ func (ctx *context) extractProg(entries []*prog.LogEntry) (*Result, error) { // Programs are executed in reverse order, usually the last program is the guilty one. res, err := ctx.extractProgSingle(reverseEntries(lastEntries), timeout) if err != nil { - return res, err + return nil, err } if res != nil { ctx.reproLog(3, "found reproducer with %d syscalls", len(res.Prog.Calls)) @@ -247,7 +254,7 @@ func (ctx *context) extractProg(entries []*prog.LogEntry) (*Result, error) { // Execute all programs and bisect the log to find multiple guilty programs. res, err = ctx.extractProgBisect(reverseEntries(entries), timeout) if err != nil { - return res, err + return nil, err } if res != nil { ctx.reproLog(3, "found reproducer with %d syscalls", len(res.Prog.Calls)) @@ -424,60 +431,31 @@ func (ctx *context) simplifyProg(res *Result) (*Result, error) { ctx.stats.SimplifyProgTime = time.Since(start) }() - opts := res.Opts - opts.Collide = false - crashed, err := ctx.testProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - opts.Threaded = false - crashed, err := ctx.testProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - } - } - if res.Opts.Sandbox == "namespace" { - opts = res.Opts - opts.Sandbox = "none" - crashed, err := ctx.testProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - } - } - if res.Opts.Procs > 1 { - opts = res.Opts - opts.Procs = 1 - crashed, err := ctx.testProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - } - } - if res.Opts.Repeat { - opts = res.Opts - opts.Repeat = false - crashed, err := ctx.testProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts + for _, simplify := range progSimplifies { + opts := res.Opts + if simplify(&opts) { + crashed, err := ctx.testProg(res.Prog, res.Duration, opts) + if err != nil { + return nil, err + } + if crashed { + res.Opts = opts + // Simplification successfull, try extracting C repro. + res, err := ctx.extractC(res) + if err != nil { + return nil, err + } + if res.CRepro { + return res, nil + } + } } } return res, nil } +// Try triggering crash with a C reproducer. func (ctx *context) extractC(res *Result) (*Result, error) { ctx.reproLog(2, "extracting C reproducer") start := time.Now() @@ -485,15 +463,15 @@ func (ctx *context) extractC(res *Result) (*Result, error) { ctx.stats.ExtractCTime = time.Since(start) }() - // Try triggering crash with a C reproducer. crashed, err := ctx.testCProg(res.Prog, res.Duration, res.Opts) if err != nil { - return res, err + return nil, err } res.CRepro = crashed return res, nil } +// Try to simplify the C reproducer. func (ctx *context) simplifyC(res *Result) (*Result, error) { ctx.reproLog(2, "simplifying C reproducer") start := time.Now() @@ -501,74 +479,18 @@ func (ctx *context) simplifyC(res *Result) (*Result, error) { ctx.stats.SimplifyCTime = time.Since(start) }() - // Try to simplify the C reproducer. - if res.Opts.EnableTun { - opts := res.Opts - opts.EnableTun = false - crashed, err := ctx.testCProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - } - } - if res.Opts.Sandbox != "" { - opts := res.Opts - opts.Sandbox = "" - crashed, err := ctx.testCProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - } - } - if res.Opts.UseTmpDir { - opts := res.Opts - opts.UseTmpDir = false - crashed, err := ctx.testCProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - } - } - if res.Opts.HandleSegv { + for _, simplify := range cSimplifies { opts := res.Opts - opts.HandleSegv = false - crashed, err := ctx.testCProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - } - } - if res.Opts.WaitRepeat { - opts := res.Opts - opts.WaitRepeat = false - crashed, err := ctx.testCProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts - } - } - if res.Opts.Debug { - opts := res.Opts - opts.Debug = false - crashed, err := ctx.testCProg(res.Prog, res.Duration, opts) - if err != nil { - return res, err - } - if crashed { - res.Opts = opts + if simplify(&opts) { + crashed, err := ctx.testCProg(res.Prog, res.Duration, opts) + if err != nil { + return nil, err + } + if crashed { + res.Opts = opts + } } } - return res, nil } @@ -818,3 +740,88 @@ func encodeEntries(entries []*prog.LogEntry) []byte { } return buf.Bytes() } + +type Simplify func(opts *csource.Options) bool + +var progSimplifies = []Simplify{ + func(opts *csource.Options) bool { + if !opts.Collide { + return false + } + opts.Collide = false + return true + }, + func(opts *csource.Options) bool { + if opts.Collide || !opts.Threaded { + return false + } + opts.Collide = false + return true + }, + func(opts *csource.Options) bool { + if !opts.Repeat { + return false + } + opts.Repeat = false + return true + }, + func(opts *csource.Options) bool { + if opts.Procs == 1 { + return false + } + opts.Procs = 1 + return true + }, + func(opts *csource.Options) bool { + if opts.Sandbox == "none" { + return false + } + opts.Sandbox = "none" + return true + }, +} + +var cSimplifies = append(progSimplifies, []Simplify{ + func(opts *csource.Options) bool { + if opts.Sandbox == "" { + return false + } + opts.Sandbox = "" + return true + }, + func(opts *csource.Options) bool { + if !opts.EnableTun { + return false + } + opts.EnableTun = false + return true + }, + func(opts *csource.Options) bool { + if !opts.UseTmpDir { + return false + } + opts.UseTmpDir = false + return true + }, + func(opts *csource.Options) bool { + if !opts.HandleSegv { + return false + } + opts.HandleSegv = false + return true + }, + func(opts *csource.Options) bool { + if !opts.WaitRepeat { + return false + } + opts.WaitRepeat = false + return true + }, + func(opts *csource.Options) bool { + if !opts.Debug { + return false + } + opts.Debug = false + return true + }, +}...) -- cgit mrf-deployment From e83310d8a2b1bb6418d041c8e48aad4ae2a8ae81 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 5 Jul 2017 16:23:30 +0200 Subject: pkg/csource: make all usleeps random We can't know the exact values of those sleeps in advance, they can be different for different bugs. Making them random increases the chance that the C repro executes with the right timings at some point. --- executor/common.h | 2 -- pkg/csource/common.go | 2 -- pkg/csource/csource.go | 4 ++-- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'pkg') diff --git a/executor/common.h b/executor/common.h index e1cc3385e..b087978a5 100644 --- a/executor/common.h +++ b/executor/common.h @@ -13,8 +13,6 @@ #include #if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) #include -#endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_COLLIDE) #include #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) diff --git a/pkg/csource/common.go b/pkg/csource/common.go index 90b1943fc..a2fcd6897 100644 --- a/pkg/csource/common.go +++ b/pkg/csource/common.go @@ -14,8 +14,6 @@ var commonHeader = ` #include #if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) #include -#endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_COLLIDE) #include #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index e52be3e88..32415e982 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -219,7 +219,7 @@ func generateTestFunc(w io.Writer, opts Options, calls []string, name string) { } fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", len(calls)) fmt.Fprintf(w, "\t\tpthread_create(&th[i], 0, thr, (void*)i);\n") - fmt.Fprintf(w, "\t\tusleep(10000);\n") + fmt.Fprintf(w, "\t\tusleep(rand()%%10000);\n") fmt.Fprintf(w, "\t}\n") if opts.Collide { fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", len(calls)) @@ -228,7 +228,7 @@ func generateTestFunc(w io.Writer, opts Options, calls []string, name string) { fmt.Fprintf(w, "\t\t\tusleep(rand()%%10000);\n") fmt.Fprintf(w, "\t}\n") } - fmt.Fprintf(w, "\tusleep(100000);\n") + fmt.Fprintf(w, "\tusleep(rand()%%100000);\n") fmt.Fprintf(w, "}\n\n") } } -- cgit mrf-deployment From 0d9ae38d5d5eb21cadc39a56d1272b40755bb6a3 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 19 Jul 2017 16:57:16 +0200 Subject: pkg/repro: disable Debug flag by default --- pkg/repro/repro.go | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) (limited to 'pkg') diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go index 2fbd42e14..3bab0d603 100644 --- a/pkg/repro/repro.go +++ b/pkg/repro/repro.go @@ -266,9 +266,7 @@ func (ctx *context) extractProg(entries []*prog.LogEntry) (*Result, error) { return nil, nil } -func (ctx *context) extractProgSingle(entries []*prog.LogEntry, duration time.Duration) (*Result, error) { - ctx.reproLog(3, "single: executing %d programs separately with timeout %s", len(entries), duration) - +func (ctx *context) createDefaultOps() csource.Options { opts := csource.Options{ Threaded: true, Collide: true, @@ -279,9 +277,15 @@ func (ctx *context) extractProgSingle(entries []*prog.LogEntry, duration time.Du UseTmpDir: true, HandleSegv: true, WaitRepeat: true, - Debug: true, Repro: true, } + return opts +} + +func (ctx *context) extractProgSingle(entries []*prog.LogEntry, duration time.Duration) (*Result, error) { + ctx.reproLog(3, "single: executing %d programs separately with timeout %s", len(entries), duration) + + opts := ctx.createDefaultOps() for _, ent := range entries { opts.Fault = ent.Fault @@ -312,19 +316,7 @@ func (ctx *context) extractProgSingle(entries []*prog.LogEntry, duration time.Du func (ctx *context) extractProgBisect(entries []*prog.LogEntry, baseDuration time.Duration) (*Result, error) { ctx.reproLog(3, "bisect: bisecting %d programs with base timeout %s", len(entries), baseDuration) - opts := csource.Options{ - Threaded: true, - Collide: true, - Repeat: true, - Procs: ctx.cfg.Procs, - Sandbox: ctx.cfg.Sandbox, - EnableTun: true, - UseTmpDir: true, - HandleSegv: true, - WaitRepeat: true, - Debug: true, - Repro: true, - } + opts := ctx.createDefaultOps() duration := func(entries int) time.Duration { return baseDuration + time.Duration((entries/4))*time.Second @@ -817,11 +809,4 @@ var cSimplifies = append(progSimplifies, []Simplify{ opts.WaitRepeat = false return true }, - func(opts *csource.Options) bool { - if !opts.Debug { - return false - } - opts.Debug = false - return true - }, }...) -- cgit mrf-deployment