aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/instance/execprog.go
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2022-03-31 18:26:42 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2022-04-29 17:16:33 +0200
commita04ae3093de7eebc147770fe38a5bda96b5c0634 (patch)
tree5d7062a73b354b5f1906847835e1c00804a572a5 /pkg/instance/execprog.go
parent7f2625f8905f7d981475fa314c3d06c56c7bd4b0 (diff)
all: use the same prog execution code throughout the project
Previously it was copypasted in pkg/instance, pkg/repro, tools/syz-crash. Use the single implementation instead. Also, this commit fixes a bug - the previous code always set collide to true while reproducing a bug, which led to an immediate syz-exexprog's exit. As a result, newer bugs with .syz repro only were never actually reproduced on #syz test requests.
Diffstat (limited to 'pkg/instance/execprog.go')
-rw-r--r--pkg/instance/execprog.go159
1 files changed, 159 insertions, 0 deletions
diff --git a/pkg/instance/execprog.go b/pkg/instance/execprog.go
new file mode 100644
index 000000000..7610298a6
--- /dev/null
+++ b/pkg/instance/execprog.go
@@ -0,0 +1,159 @@
+// Copyright 2022 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package instance
+
+import (
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/google/syzkaller/pkg/csource"
+ "github.com/google/syzkaller/pkg/mgrconfig"
+ "github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/pkg/report"
+ "github.com/google/syzkaller/prog"
+ "github.com/google/syzkaller/vm"
+)
+
+type ExecutorLogger func(int, string, ...interface{})
+
+type OptionalConfig struct {
+ ExitCondition vm.ExitCondition
+ Logf ExecutorLogger
+ OldFlagsCompatMode bool
+}
+
+type ExecProgInstance struct {
+ execprogBin string
+ executorBin string
+ reporter *report.Reporter
+ mgrCfg *mgrconfig.Config
+ VMInstance *vm.Instance
+ OptionalConfig
+}
+
+type RunResult struct {
+ Report *report.Report
+}
+
+func SetupExecProg(vmInst *vm.Instance, mgrCfg *mgrconfig.Config, reporter *report.Reporter,
+ opt *OptionalConfig) (*ExecProgInstance, error) {
+ execprogBin, err := vmInst.Copy(mgrCfg.ExecprogBin)
+ if err != nil {
+ vmInst.Close()
+ return nil, &TestError{Title: fmt.Sprintf("failed to copy syz-execprog to VM: %v", err)}
+ }
+ executorBin := mgrCfg.SysTarget.ExecutorBin
+ if executorBin == "" {
+ executorBin, err = vmInst.Copy(mgrCfg.ExecutorBin)
+ if err != nil {
+ vmInst.Close()
+ return nil, &TestError{Title: fmt.Sprintf("failed to copy syz-executor to VM: %v", err)}
+ }
+ }
+ ret := &ExecProgInstance{
+ execprogBin: execprogBin,
+ executorBin: executorBin,
+ reporter: reporter,
+ mgrCfg: mgrCfg,
+ VMInstance: vmInst,
+ }
+ if opt != nil {
+ ret.OptionalConfig = *opt
+ }
+ if ret.Logf == nil {
+ ret.Logf = func(int, string, ...interface{}) {}
+ }
+ if ret.ExitCondition == 0 {
+ ret.ExitCondition = vm.ExitTimeout | vm.ExitNormal | vm.ExitError
+ }
+ return ret, nil
+}
+
+func CreateExecProgInstance(vmPool *vm.Pool, vmIndex int, mgrCfg *mgrconfig.Config,
+ reporter *report.Reporter, opt *OptionalConfig) (*ExecProgInstance, error) {
+ vmInst, err := vmPool.Create(vmIndex)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create VM: %v", err)
+ }
+ ret, err := SetupExecProg(vmInst, mgrCfg, reporter, opt)
+ if err != nil {
+ vmInst.Close()
+ return nil, err
+ }
+ return ret, nil
+}
+
+func (inst *ExecProgInstance) runCommand(command string, duration time.Duration) (*RunResult, error) {
+ outc, errc, err := inst.VMInstance.Run(duration, nil, command)
+ 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)
+ if result.Report == nil {
+ inst.Logf(2, "program did not crash")
+ } else {
+ if err := inst.reporter.Symbolize(result.Report); err != nil {
+ return nil, fmt.Errorf("failed to symbolize report: %v", err)
+ }
+ inst.Logf(2, "program crashed: %v", result.Report.Title)
+ }
+ return result, nil
+}
+
+func (inst *ExecProgInstance) runBinary(bin string, duration time.Duration) (*RunResult, error) {
+ bin, err := inst.VMInstance.Copy(bin)
+ if err != nil {
+ return nil, &TestError{Title: fmt.Sprintf("failed to copy binary to VM: %v", err)}
+ }
+ return inst.runCommand(bin, duration)
+}
+
+func (inst *ExecProgInstance) RunCProg(p *prog.Prog, duration time.Duration,
+ opts csource.Options) (*RunResult, error) {
+ src, err := csource.Write(p, opts)
+ if err != nil {
+ return nil, err
+ }
+ inst.Logf(2, "testing compiled C program (duration=%v, %+v): %s", duration, opts, p)
+ return inst.RunCProgRaw(src, p.Target, duration)
+}
+
+func (inst *ExecProgInstance) RunCProgRaw(src []byte, target *prog.Target,
+ duration time.Duration) (*RunResult, error) {
+ bin, err := csource.BuildNoWarn(target, src)
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(bin)
+ return inst.runBinary(bin, duration)
+}
+
+func (inst *ExecProgInstance) RunSyzProgFile(progFile string, duration time.Duration,
+ opts csource.Options) (*RunResult, error) {
+ vmProgFile, err := inst.VMInstance.Copy(progFile)
+ if err != nil {
+ return nil, &TestError{Title: fmt.Sprintf("failed to copy prog to VM: %v", err)}
+ }
+ target := inst.mgrCfg.SysTarget
+ faultCall := -1
+ if opts.Fault {
+ faultCall = opts.FaultCall
+ }
+ command := ExecprogCmd(inst.execprogBin, inst.executorBin, target.OS, target.Arch, opts.Sandbox,
+ opts.Repeat, opts.Threaded, opts.Collide, opts.Procs, faultCall, opts.FaultNth,
+ !inst.OldFlagsCompatMode, inst.mgrCfg.Timeouts.Slowdown, vmProgFile)
+ return inst.runCommand(command, duration)
+}
+
+func (inst *ExecProgInstance) RunSyzProg(syzProg []byte, duration time.Duration,
+ opts csource.Options) (*RunResult, error) {
+ progFile, err := osutil.WriteTempFile(syzProg)
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(progFile)
+ return inst.RunSyzProgFile(progFile, duration, opts)
+}