github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/instance/execprog.go (about) 1 // Copyright 2022 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package instance 5 6 import ( 7 "fmt" 8 "os" 9 "time" 10 11 "github.com/google/syzkaller/pkg/csource" 12 "github.com/google/syzkaller/pkg/mgrconfig" 13 "github.com/google/syzkaller/pkg/osutil" 14 "github.com/google/syzkaller/pkg/report" 15 "github.com/google/syzkaller/prog" 16 "github.com/google/syzkaller/sys/targets" 17 "github.com/google/syzkaller/vm" 18 ) 19 20 type ExecutorLogger func(int, string, ...interface{}) 21 22 type OptionalConfig struct { 23 ExitCondition vm.ExitCondition 24 Logf ExecutorLogger 25 OldFlagsCompatMode bool 26 BeforeContextLen int 27 StraceBin string 28 } 29 30 type ExecProgInstance struct { 31 execprogBin string 32 executorBin string 33 reporter *report.Reporter 34 mgrCfg *mgrconfig.Config 35 VMInstance *vm.Instance 36 OptionalConfig 37 } 38 39 type RunResult struct { 40 Output []byte 41 Report *report.Report 42 } 43 44 func SetupExecProg(vmInst *vm.Instance, mgrCfg *mgrconfig.Config, reporter *report.Reporter, 45 opt *OptionalConfig) (*ExecProgInstance, error) { 46 execprogBin, err := vmInst.Copy(mgrCfg.ExecprogBin) 47 if err != nil { 48 return nil, &TestError{Title: fmt.Sprintf("failed to copy syz-execprog to VM: %v", err)} 49 } 50 executorBin := mgrCfg.SysTarget.ExecutorBin 51 if executorBin == "" { 52 executorBin, err = vmInst.Copy(mgrCfg.ExecutorBin) 53 if err != nil { 54 return nil, &TestError{Title: fmt.Sprintf("failed to copy syz-executor to VM: %v", err)} 55 } 56 } 57 ret := &ExecProgInstance{ 58 execprogBin: execprogBin, 59 executorBin: executorBin, 60 reporter: reporter, 61 mgrCfg: mgrCfg, 62 VMInstance: vmInst, 63 } 64 if opt != nil { 65 ret.OptionalConfig = *opt 66 if ret.StraceBin != "" { 67 var err error 68 ret.StraceBin, err = vmInst.Copy(ret.StraceBin) 69 if err != nil { 70 return nil, &TestError{Title: fmt.Sprintf("failed to copy strace bin: %v", err)} 71 } 72 } 73 } 74 if ret.Logf == nil { 75 ret.Logf = func(int, string, ...interface{}) {} 76 } 77 if ret.ExitCondition == 0 { 78 ret.ExitCondition = vm.ExitTimeout | vm.ExitNormal | vm.ExitError 79 } 80 return ret, nil 81 } 82 83 func CreateExecProgInstance(vmPool *vm.Pool, vmIndex int, mgrCfg *mgrconfig.Config, 84 reporter *report.Reporter, opt *OptionalConfig) (*ExecProgInstance, error) { 85 vmInst, err := vmPool.Create(vmIndex) 86 if err != nil { 87 return nil, fmt.Errorf("failed to create VM: %w", err) 88 } 89 ret, err := SetupExecProg(vmInst, mgrCfg, reporter, opt) 90 if err != nil { 91 vmInst.Close() 92 return nil, err 93 } 94 return ret, nil 95 } 96 97 func (inst *ExecProgInstance) runCommand(command string, duration time.Duration) (*RunResult, error) { 98 var prefixOutput []byte 99 if inst.StraceBin != "" { 100 filterCalls := "" 101 switch inst.mgrCfg.SysTarget.OS { 102 case targets.Linux: 103 // wait4 and nanosleep generate a lot of noise, especially when running syz-executor. 104 // We cut them on the VM side in order to decrease load on the network and to use 105 // the limited buffer size wisely. 106 filterCalls = ` -e \!wait4,clock_nanosleep,nanosleep` 107 } 108 command = inst.StraceBin + filterCalls + ` -s 100 -x -f ` + command 109 prefixOutput = []byte(fmt.Sprintf("%s\n\n<...>\n", command)) 110 } 111 opts := []any{inst.ExitCondition} 112 if inst.BeforeContextLen != 0 { 113 opts = append(opts, vm.OutputSize(inst.BeforeContextLen)) 114 } 115 output, rep, err := inst.VMInstance.Run(duration, inst.reporter, command, opts...) 116 if err != nil { 117 return nil, fmt.Errorf("failed to run command in VM: %w", err) 118 } 119 if rep == nil { 120 inst.Logf(2, "program did not crash") 121 } else { 122 if err := inst.reporter.Symbolize(rep); err != nil { 123 inst.Logf(0, "failed to symbolize report: %v", err) 124 } 125 inst.Logf(2, "program crashed: %v", rep.Title) 126 } 127 result := &RunResult{append(prefixOutput, output...), rep} 128 return result, nil 129 } 130 131 func (inst *ExecProgInstance) runBinary(bin string, duration time.Duration) (*RunResult, error) { 132 bin, err := inst.VMInstance.Copy(bin) 133 if err != nil { 134 return nil, &TestError{Title: fmt.Sprintf("failed to copy binary to VM: %v", err)} 135 } 136 return inst.runCommand(bin, duration) 137 } 138 139 func (inst *ExecProgInstance) RunCProg(p *prog.Prog, duration time.Duration, 140 opts csource.Options) (*RunResult, error) { 141 src, err := csource.Write(p, opts) 142 if err != nil { 143 return nil, err 144 } 145 inst.Logf(2, "testing compiled C program (duration=%v, %+v): %s", duration, opts, p) 146 return inst.RunCProgRaw(src, p.Target, duration) 147 } 148 149 func (inst *ExecProgInstance) RunCProgRaw(src []byte, target *prog.Target, 150 duration time.Duration) (*RunResult, error) { 151 bin, err := csource.BuildNoWarn(target, src) 152 if err != nil { 153 return nil, err 154 } 155 defer os.Remove(bin) 156 return inst.runBinary(bin, duration) 157 } 158 159 func (inst *ExecProgInstance) RunSyzProgFile(progFile string, duration time.Duration, 160 opts csource.Options) (*RunResult, error) { 161 vmProgFile, err := inst.VMInstance.Copy(progFile) 162 if err != nil { 163 return nil, &TestError{Title: fmt.Sprintf("failed to copy prog to VM: %v", err)} 164 } 165 target := inst.mgrCfg.SysTarget 166 faultCall := -1 167 if opts.Fault { 168 faultCall = opts.FaultCall 169 } 170 command := ExecprogCmd(inst.execprogBin, inst.executorBin, target.OS, target.Arch, opts.Sandbox, 171 opts.SandboxArg, opts.Repeat, opts.Threaded, opts.Collide, opts.Procs, faultCall, opts.FaultNth, 172 !inst.OldFlagsCompatMode, inst.mgrCfg.Timeouts.Slowdown, vmProgFile) 173 return inst.runCommand(command, duration) 174 } 175 176 func (inst *ExecProgInstance) RunSyzProg(syzProg []byte, duration time.Duration, 177 opts csource.Options) (*RunResult, error) { 178 progFile, err := osutil.WriteTempFile(syzProg) 179 if err != nil { 180 return nil, err 181 } 182 defer os.Remove(progFile) 183 return inst.RunSyzProgFile(progFile, duration, opts) 184 } 185 186 func (inst *ExecProgInstance) Close() { 187 inst.VMInstance.Close() 188 }