aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2022-04-19 10:16:51 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2022-04-29 17:16:33 +0200
commit33d1aba90b07c4319e1617be24f6f6dfd1b71d5e (patch)
tree3c0269519b2f2dfc50476d065a43a82d0137c3f8
parenta04ae3093de7eebc147770fe38a5bda96b5c0634 (diff)
vm: support variable output buffer size
Also update syz-crush to save RawOutput instead of output from the Report.
-rw-r--r--pkg/instance/execprog.go9
-rw-r--r--tools/syz-crush/crush.go11
-rw-r--r--vm/vm.go78
-rw-r--r--vm/vm_test.go2
4 files changed, 63 insertions, 37 deletions
diff --git a/pkg/instance/execprog.go b/pkg/instance/execprog.go
index 7610298a6..1d775c22c 100644
--- a/pkg/instance/execprog.go
+++ b/pkg/instance/execprog.go
@@ -22,6 +22,7 @@ type OptionalConfig struct {
ExitCondition vm.ExitCondition
Logf ExecutorLogger
OldFlagsCompatMode bool
+ BeforeContextLen int
}
type ExecProgInstance struct {
@@ -34,7 +35,7 @@ type ExecProgInstance struct {
}
type RunResult struct {
- Report *report.Report
+ vm.ExecutionResult
}
func SetupExecProg(vmInst *vm.Instance, mgrCfg *mgrconfig.Config, reporter *report.Reporter,
@@ -90,8 +91,10 @@ func (inst *ExecProgInstance) runCommand(command string, duration time.Duration)
if err != nil {
return nil, fmt.Errorf("failed to run command in VM: %v", err)
}
- result := &RunResult{}
- result.Report = inst.VMInstance.MonitorExecution(outc, errc, inst.reporter, inst.ExitCondition)
+ result := &RunResult{
+ ExecutionResult: *inst.VMInstance.MonitorExecutionRaw(outc, errc,
+ inst.reporter, inst.ExitCondition, inst.BeforeContextLen),
+ }
if result.Report == nil {
inst.Logf(2, "program did not crash")
} else {
diff --git a/tools/syz-crush/crush.go b/tools/syz-crush/crush.go
index ac077befd..36424c61a 100644
--- a/tools/syz-crush/crush.go
+++ b/tools/syz-crush/crush.go
@@ -83,7 +83,7 @@ func main() {
log.Printf("reproducing from log file: %v", reproduceMe)
}
log.Printf("booting %v test machines...", vmPool.Count())
- runDone := make(chan *report.Report)
+ runDone := make(chan *instance.RunResult)
var shutdown, stoppedWorkers uint32
for i := 0; i < vmPool.Count(); i++ {
@@ -124,7 +124,8 @@ func main() {
log.Printf("all done. reproduced %v crashes. reproduce rate %.2f%%", crashes, float64(crashes)/float64(count)*100.0)
}
-func storeCrash(cfg *mgrconfig.Config, rep *report.Report) {
+func storeCrash(cfg *mgrconfig.Config, res *instance.RunResult) {
+ rep := res.Report
id := hash.String([]byte(rep.Title))
dir := filepath.Join(filepath.Dir(flag.Args()[0]), "crashes", id)
osutil.MkdirAll(dir)
@@ -137,7 +138,7 @@ func storeCrash(cfg *mgrconfig.Config, rep *report.Report) {
if err := osutil.WriteFile(filepath.Join(dir, "description"), []byte(rep.Title+"\n")); err != nil {
log.Printf("failed to write crash description: %v", err)
}
- if err := osutil.WriteFile(filepath.Join(dir, fmt.Sprintf("log%v", index)), rep.Output); err != nil {
+ if err := osutil.WriteFile(filepath.Join(dir, fmt.Sprintf("log%v", index)), res.RawOutput); err != nil {
log.Printf("failed to write crash log: %v", err)
}
if err := osutil.WriteFile(filepath.Join(dir, fmt.Sprintf("tag%v", index)), []byte(cfg.Tag)); err != nil {
@@ -154,7 +155,7 @@ func storeCrash(cfg *mgrconfig.Config, rep *report.Report) {
}
func runInstance(cfg *mgrconfig.Config, reporter *report.Reporter,
- vmPool *vm.Pool, index int, timeout time.Duration, runType FileType) *report.Report {
+ vmPool *vm.Pool, index int, timeout time.Duration, runType FileType) *instance.RunResult {
log.Printf("vm-%v: starting", index)
optArgs := &instance.OptionalConfig{
ExitCondition: vm.ExitTimeout,
@@ -186,7 +187,7 @@ func runInstance(cfg *mgrconfig.Config, reporter *report.Reporter,
}
if res.Report != nil {
log.Printf("vm-%v: crash: %v", index, res.Report.Title)
- return res.Report
+ return res
}
log.Printf("vm-%v: running long enough, stopping", index)
return nil
diff --git a/vm/vm.go b/vm/vm.go
index 518319521..61020b6ed 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -181,19 +181,51 @@ const (
// Returns a non-symbolized crash report, or nil if no error happens.
func (inst *Instance) MonitorExecution(outc <-chan []byte, errc <-chan error,
reporter *report.Reporter, exit ExitCondition) (rep *report.Report) {
+ return inst.MonitorExecutionRaw(outc, errc, reporter, exit, 0).Report
+}
+
+type ExecutionResult struct {
+ Report *report.Report
+ RawOutput []byte
+}
+
+func (inst *Instance) MonitorExecutionRaw(outc <-chan []byte, errc <-chan error,
+ reporter *report.Reporter, exit ExitCondition, beforeContextSize int) (res *ExecutionResult) {
+ if beforeContextSize == 0 {
+ beforeContextSize = beforeContextDefault
+ }
mon := &monitor{
- inst: inst,
- outc: outc,
- errc: errc,
- reporter: reporter,
- exit: exit,
+ inst: inst,
+ outc: outc,
+ errc: errc,
+ reporter: reporter,
+ beforeContext: beforeContextSize,
+ exit: exit,
}
- lastExecuteTime := time.Now()
- ticker := time.NewTicker(tickerPeriod * inst.timeouts.Scale)
+ return &ExecutionResult{
+ Report: mon.monitorExecution(),
+ RawOutput: mon.output,
+ }
+}
+
+type monitor struct {
+ inst *Instance
+ outc <-chan []byte
+ errc <-chan error
+ reporter *report.Reporter
+ exit ExitCondition
+ output []byte
+ beforeContext int
+ matchPos int
+}
+
+func (mon *monitor) monitorExecution() *report.Report {
+ ticker := time.NewTicker(tickerPeriod * mon.inst.timeouts.Scale)
defer ticker.Stop()
+ lastExecuteTime := time.Now()
for {
select {
- case err := <-errc:
+ case err := <-mon.errc:
switch err {
case nil:
// The program has exited without errors,
@@ -217,9 +249,9 @@ func (inst *Instance) MonitorExecution(outc <-chan []byte, errc <-chan error,
}
return mon.extractError(crash)
}
- case out, ok := <-outc:
+ case out, ok := <-mon.outc:
if !ok {
- outc = nil
+ mon.outc = nil
continue
}
lastPos := len(mon.output)
@@ -228,12 +260,12 @@ func (inst *Instance) MonitorExecution(outc <-chan []byte, errc <-chan error,
bytes.Contains(mon.output[lastPos:], executingProgram2) {
lastExecuteTime = time.Now()
}
- if reporter.ContainsCrash(mon.output[mon.matchPos:]) {
+ if mon.reporter.ContainsCrash(mon.output[mon.matchPos:]) {
return mon.extractError("unknown error")
}
- if len(mon.output) > 2*beforeContext {
- copy(mon.output, mon.output[len(mon.output)-beforeContext:])
- mon.output = mon.output[:beforeContext]
+ if len(mon.output) > 2*mon.beforeContext {
+ copy(mon.output, mon.output[len(mon.output)-mon.beforeContext:])
+ mon.output = mon.output[:mon.beforeContext]
}
// Find the starting position for crash matching on the next iteration.
// We step back from the end of output by maxErrorLength to handle the case
@@ -254,7 +286,7 @@ func (inst *Instance) MonitorExecution(outc <-chan []byte, errc <-chan error,
case <-ticker.C:
// Detect both "no output whatsoever" and "kernel episodically prints
// something to console, but fuzzer is not actually executing programs".
- if time.Since(lastExecuteTime) > inst.timeouts.NoOutput {
+ if time.Since(lastExecuteTime) > mon.inst.timeouts.NoOutput {
return mon.extractError(noOutputCrash)
}
case <-Shutdown:
@@ -263,16 +295,6 @@ func (inst *Instance) MonitorExecution(outc <-chan []byte, errc <-chan error,
}
}
-type monitor struct {
- inst *Instance
- outc <-chan []byte
- errc <-chan error
- reporter *report.Reporter
- exit ExitCondition
- output []byte
- matchPos int
-}
-
func (mon *monitor) extractError(defaultError string) *report.Report {
diagOutput, diagWait := []byte{}, false
if defaultError != "" {
@@ -316,7 +338,7 @@ func (mon *monitor) createReport(defaultError string) *report.Report {
Suppressed: report.IsSuppressed(mon.reporter, mon.output),
}
}
- start := rep.StartPos - beforeContext
+ start := rep.StartPos - mon.beforeContext
if start < 0 {
start = 0
}
@@ -362,8 +384,8 @@ var (
executingProgram1 = []byte("executing program") // syz-fuzzer, syz-runner output
executingProgram2 = []byte("executed programs:") // syz-execprog output
- beforeContext = 1024 << 10
- afterContext = 128 << 10
+ beforeContextDefault = 1024 << 10
+ afterContext = 128 << 10
tickerPeriod = 10 * time.Second
waitForOutputTimeout = 10 * time.Second
diff --git a/vm/vm_test.go b/vm/vm_test.go
index 83c3f51eb..2bcbbc1db 100644
--- a/vm/vm_test.go
+++ b/vm/vm_test.go
@@ -69,7 +69,7 @@ func (inst *testInstance) Close() {
}
func init() {
- beforeContext = maxErrorLength + 100
+ beforeContextDefault = maxErrorLength + 100
tickerPeriod = 1 * time.Second
waitForOutputTimeout = 3 * time.Second