func testProg(cfg *config.Config, p *prog.Prog, multiplier int, threaded, collide bool) (res bool) { log.Printf("booting VM") inst := <-instances defer func() { returnInstance(inst, res) }() pstr := p.Serialize() progFile, err := fileutil.WriteTempFile(pstr) if err != nil { log.Fatalf("%v", err) } defer os.Remove(progFile) bin, err := inst.Copy(progFile) if err != nil { log.Fatalf("failed to copy to VM: %v", err) } repeat := 100 timeoutSec := 10 * repeat / cfg.Procs if threaded { repeat *= 10 timeoutSec *= 1 } repeat *= multiplier timeoutSec *= multiplier timeout := time.Duration(timeoutSec) * time.Second command := fmt.Sprintf("%v -executor %v -cover=0 -procs=%v -repeat=%v -threaded=%v -collide=%v %v", inst.execprogBin, inst.executorBin, cfg.Procs, repeat, threaded, collide, bin) log.Printf("testing program (threaded=%v, collide=%v, repeat=%v, timeout=%v):\n%s\n", threaded, collide, repeat, timeout, pstr) return testImpl(inst, command, timeout) }
func execute(pid int, env *ipc.Env, p *prog.Prog) { if *flagExecutor == "" { return } atomic.AddUint64(&statExec, 1) if *flagLogProg { ticket := gate.Enter() defer gate.Leave(ticket) outMu.Lock() fmt.Printf("executing program %v\n%s\n", pid, p.Serialize()) outMu.Unlock() } output, _, _, failed, hanged, err := env.Exec(p) if err != nil { fmt.Printf("failed to execute executor: %v\n", err) } paniced := failedRe.Match(output) if failed || hanged || paniced || err != nil { fmt.Printf("PROGRAM:\n%s\n", p.Serialize()) } if failed || hanged || paniced || err != nil || *flagOutput { os.Stdout.Write(output) } }
func (ctx *context) testProg(p *prog.Prog, duration time.Duration, opts csource.Options, reboot bool) (crashed bool, err error) { inst := <-ctx.instances if inst == nil { return false, fmt.Errorf("all VMs failed to boot") } defer func() { ctx.returnInstance(inst, reboot, crashed) }() pstr := p.Serialize() progFile, err := fileutil.WriteTempFile(pstr) if err != nil { return false, err } defer os.Remove(progFile) vmProgFile, err := inst.Copy(progFile) if err != nil { return false, fmt.Errorf("failed to copy to VM: %v", err) } repeat := "1" if opts.Repeat { repeat = "0" } command := fmt.Sprintf("%v -executor %v -cover=0 -procs=%v -repeat=%v -sandbox %v -threaded=%v -collide=%v %v", inst.execprogBin, inst.executorBin, opts.Procs, repeat, opts.Sandbox, opts.Threaded, opts.Collide, vmProgFile) Logf(2, "reproducing crash '%v': testing program (duration=%v, %+v): %s", ctx.crashDesc, duration, opts, p) return ctx.testImpl(inst, command, duration) }
func testOne(t *testing.T, p *prog.Prog, opts Options) { src := Write(p, opts) srcf, err := fileutil.WriteTempFile(src) if err != nil { t.Logf("program:\n%s\n", p.Serialize()) t.Fatalf("%v", err) } defer os.Remove(srcf) bin, err := Build(srcf) if err != nil { t.Logf("program:\n%s\n", p.Serialize()) t.Fatalf("%v", err) } defer os.Remove(bin) }
func execute(env *ipc.Env, p *prog.Prog) { if *flagExecutor == "" { return } output, _, _, _, _, err := env.Exec(p) if err != nil { fmt.Printf("failed to execute executor: %v\n", err) } failed := failedRe.Match(output) if failed { fmt.Printf("PROGRAM:\n%s\n", p.Serialize()) } if failed || *flagOutput { os.Stdout.Write(output) } }
func execute1(env *ipc.Env, p *prog.Prog, stat *uint64) []cover.Cover { if *flagSaveProg { f, err := os.Create(fmt.Sprintf("%v.prog", *flagName)) if err == nil { f.Write(p.Serialize()) f.Close() } } else { // The following output helps to understand what program crashed kernel. // It must not be intermixed. logMu.Lock() log.Printf("executing program:\n%s", p.Serialize()) logMu.Unlock() } try := 0 retry: *stat++ output, strace, rawCover, failed, hanged, err := env.Exec(p) if err != nil { if try > 10 { panic(err) } try++ debug.FreeOSMemory() time.Sleep(time.Second) goto retry } logf(4, "result failed=%v hanged=%v:\n%v\n", failed, hanged, string(output)) if len(strace) != 0 { logf(4, "strace:\n%s\n", strace) } cov := make([]cover.Cover, len(p.Calls)) for i, c := range rawCover { cov[i] = cover.Cover(c) } return cov }
func execute1(pid int, env *ipc.Env, p *prog.Prog, stat *uint64) []cover.Cover { if false { // For debugging, this function must not be executed with locks held. corpusMu.Lock() corpusMu.Unlock() coverMu.Lock() coverMu.Unlock() triageMu.Lock() triageMu.Unlock() } // Limit concurrency window and do leak checking once in a while. idx := gate.Enter() defer gate.Leave(idx, func() { if idx == 0 && *flagLeak && atomic.LoadUint32(&allTriaged) != 0 { // Scan for leaks once in a while (it is damn slow). kmemleakScan(true) } }) // The following output helps to understand what program crashed kernel. // It must not be intermixed. switch *flagOutput { case "none": // This case intentionally left blank. case "stdout": data := p.Serialize() logMu.Lock() log.Printf("executing program %v:\n%s", pid, data) logMu.Unlock() case "dmesg": fd, err := syscall.Open("/dev/kmsg", syscall.O_WRONLY, 0) if err == nil { buf := new(bytes.Buffer) fmt.Fprintf(buf, "syzkaller: executing program %v:\n%s", pid, p.Serialize()) syscall.Write(fd, buf.Bytes()) syscall.Close(fd) } case "file": f, err := os.Create(fmt.Sprintf("%v-%v.prog", *flagName, pid)) if err == nil { f.Write(p.Serialize()) f.Close() } } try := 0 retry: atomic.AddUint64(stat, 1) output, rawCover, errnos, failed, hanged, err := env.Exec(p) _ = errnos if failed { // BUG in output should be recognized by manager. logf(0, "BUG: executor-detected bug:\n%s", output) // Don't return any cover so that the input is not added to corpus. return make([]cover.Cover, len(p.Calls)) } if err != nil { if try > 10 { panic(err) } try++ debug.FreeOSMemory() time.Sleep(time.Second) goto retry } logf(4, "result failed=%v hanged=%v:\n%v\n", failed, hanged, string(output)) cov := make([]cover.Cover, len(p.Calls)) for i, c := range rawCover { cov[i] = cover.Cover(c) } return cov }