| // Copyright 2016 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. |
| |
| // syz-crush replays crash log on multiple VMs. Usage: |
| // syz-crush -config=config.file execution.log |
| // Intended for reproduction of particularly elusive crashes. |
| package main |
| |
| import ( |
| "flag" |
| "io/ioutil" |
| "sync" |
| "sync/atomic" |
| "time" |
| |
| "github.com/google/syzkaller/pkg/instance" |
| "github.com/google/syzkaller/pkg/log" |
| "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" |
| ) |
| |
| var ( |
| flagConfig = flag.String("config", "", "configuration file") |
| ) |
| |
| func main() { |
| flag.Parse() |
| cfg, err := mgrconfig.LoadFile(*flagConfig) |
| if err != nil { |
| log.Fatalf("%v", err) |
| } |
| if len(flag.Args()) != 1 { |
| log.Fatalf("usage: syz-crush -config=config.file execution.log") |
| } |
| if _, err := prog.GetTarget(cfg.TargetOS, cfg.TargetArch); err != nil { |
| log.Fatalf("%v", err) |
| } |
| vmPool, err := vm.Create(cfg, false) |
| if err != nil { |
| log.Fatalf("%v", err) |
| } |
| reporter, err := report.NewReporter(cfg) |
| if err != nil { |
| log.Fatalf("%v", err) |
| } |
| |
| log.Logf(0, "booting test machines...") |
| var shutdown uint32 |
| var wg sync.WaitGroup |
| wg.Add(vmPool.Count() + 1) |
| for i := 0; i < vmPool.Count(); i++ { |
| i := i |
| go func() { |
| defer wg.Done() |
| for { |
| runInstance(cfg, reporter, vmPool, i) |
| if atomic.LoadUint32(&shutdown) != 0 { |
| break |
| } |
| } |
| }() |
| } |
| |
| shutdownC := make(chan struct{}) |
| osutil.HandleInterrupts(shutdownC) |
| go func() { |
| <-shutdownC |
| wg.Done() |
| atomic.StoreUint32(&shutdown, 1) |
| }() |
| wg.Wait() |
| } |
| |
| func runInstance(cfg *mgrconfig.Config, reporter report.Reporter, vmPool *vm.Pool, index int) { |
| inst, err := vmPool.Create(index) |
| if err != nil { |
| log.Logf(0, "failed to create instance: %v", err) |
| return |
| } |
| defer inst.Close() |
| |
| execprogBin, err := inst.Copy(cfg.SyzExecprogBin) |
| if err != nil { |
| log.Logf(0, "failed to copy execprog: %v", err) |
| return |
| } |
| executorBin, err := inst.Copy(cfg.SyzExecutorBin) |
| if err != nil { |
| log.Logf(0, "failed to copy executor: %v", err) |
| return |
| } |
| logFile, err := inst.Copy(flag.Args()[0]) |
| if err != nil { |
| log.Logf(0, "failed to copy log: %v", err) |
| return |
| } |
| |
| cmd := instance.ExecprogCmd(execprogBin, executorBin, cfg.TargetOS, cfg.TargetArch, cfg.Sandbox, |
| true, true, true, cfg.Procs, -1, -1, logFile) |
| outc, errc, err := inst.Run(time.Hour, nil, cmd) |
| if err != nil { |
| log.Logf(0, "failed to run execprog: %v", err) |
| return |
| } |
| |
| log.Logf(0, "vm-%v: crushing...", index) |
| rep := inst.MonitorExecution(outc, errc, reporter, false) |
| if rep == nil { |
| // This is the only "OK" outcome. |
| log.Logf(0, "vm-%v: running long enough, restarting", index) |
| } else { |
| f, err := ioutil.TempFile(".", "syz-crush") |
| if err != nil { |
| log.Logf(0, "failed to create temp file: %v", err) |
| return |
| } |
| defer f.Close() |
| log.Logf(0, "vm-%v: crashed: %v, saving to %v", index, rep.Title, f.Name()) |
| f.Write(rep.Output) |
| } |
| } |