func main() { flag.Parse() if len(flag.Args()) != 1 { fmt.Fprintf(os.Stderr, "usage: syz-symbolize [flags] kernel_log_file\n") flag.PrintDefaults() os.Exit(1) } text, err := ioutil.ReadFile(flag.Args()[0]) if err != nil { fmt.Fprintf(os.Stderr, "failed to open input file: %v\n", err) os.Exit(1) } if _, parsed, _, _ := report.Parse(text, nil); len(parsed) != 0 { text = parsed } text, err = report.Symbolize(filepath.Join(*flagLinux, "vmlinux"), text) if err != nil { fmt.Fprintf(os.Stderr, "failed to symbolize: %v\n", err) os.Exit(1) } os.Stdout.Write(text) }
func main() { if len(os.Args) != 3 { fmt.Fprintf(os.Stderr, "usage: syz-report vmlinux report (args %+v)\n", os.Args) os.Exit(1) } output, err := ioutil.ReadFile(os.Args[2]) if err != nil { fmt.Fprintf(os.Stderr, "failed to read report file: %v\n", err) os.Exit(1) } desc, text, _, _ := report.Parse(output) if desc == "" { fmt.Fprintf(os.Stderr, "report file does not contain a crash\n") os.Exit(1) } symbolized, err := report.Symbolize(os.Args[1], text) if err != nil { fmt.Fprintf(os.Stderr, "failed to symbolize report: %v\n", err) } else { text = symbolized } fmt.Printf("%v\n\n%s", desc, text) }
func Run(crashLog []byte, cfg *config.Config, vmIndexes []int) (*Result, error) { if len(vmIndexes) == 0 { return nil, fmt.Errorf("no VMs provided") } if _, err := os.Stat(filepath.Join(cfg.Syzkaller, "bin/syz-execprog")); err != nil { return nil, fmt.Errorf("bin/syz-execprog is missing (run 'make execprog')") } entries := prog.ParseLog(crashLog) if len(entries) == 0 { return nil, fmt.Errorf("crash log does not contain any programs") } crashDesc, _, crashStart, _ := report.Parse(crashLog, cfg.ParsedIgnores) if crashDesc == "" { crashStart = len(crashLog) // assuming VM hanged crashDesc = "hang" } Logf(0, "reproducing crash '%v': %v programs, %v VMs", crashDesc, len(entries), len(vmIndexes)) ctx := &context{ cfg: cfg, crashDesc: crashDesc, instances: make(chan *instance, len(vmIndexes)), bootRequests: make(chan int, len(vmIndexes)), } var wg sync.WaitGroup wg.Add(len(vmIndexes)) for _, vmIndex := range vmIndexes { ctx.bootRequests <- vmIndex go func() { defer wg.Done() for vmIndex := range ctx.bootRequests { var inst *instance for try := 0; try < 3; try++ { vmCfg, err := config.CreateVMConfig(cfg, vmIndex) if err != nil { Logf(0, "reproducing crash '%v': failed to create VM config: %v", crashDesc, err) time.Sleep(10 * time.Second) continue } vmInst, err := vm.Create(cfg.Type, vmCfg) if err != nil { Logf(0, "reproducing crash '%v': failed to create VM: %v", crashDesc, err) time.Sleep(10 * time.Second) continue } execprogBin, err := vmInst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-execprog")) if err != nil { Logf(0, "reproducing crash '%v': failed to copy to VM: %v", crashDesc, err) vmInst.Close() time.Sleep(10 * time.Second) continue } executorBin, err := vmInst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-executor")) if err != nil { Logf(0, "reproducing crash '%v': failed to copy to VM: %v", crashDesc, err) vmInst.Close() time.Sleep(10 * time.Second) continue } inst = &instance{vmInst, vmIndex, execprogBin, executorBin} break } if inst == nil { break } ctx.instances <- inst } }() } go func() { wg.Wait() close(ctx.instances) }() res, err := ctx.repro(entries, crashStart) close(ctx.bootRequests) for inst := range ctx.instances { inst.Close() } return res, err }
func main() { flag.Parse() cfg, _, _, err := config.Parse(*flagConfig) if err != nil { Fatalf("%v", err) } if *flagCount > 0 { cfg.Count = *flagCount } if _, err := os.Stat(filepath.Join(cfg.Syzkaller, "bin/syz-execprog")); err != nil { Fatalf("bin/syz-execprog is missing (run 'make execprog')") } if len(flag.Args()) != 1 { Fatalf("usage: syz-repro -config=config.file execution.log") } data, err := ioutil.ReadFile(flag.Args()[0]) if err != nil { Fatalf("failed to open log file: %v", err) } entries := prog.ParseLog(data) Logf(0, "parsed %v programs", len(entries)) crashDesc, _, crashStart, _ := report.Parse(data) if crashDesc == "" { crashStart = len(data) // assuming VM hanged } instances = make(chan VM, cfg.Count) bootRequests = make(chan int, cfg.Count) for i := 0; i < cfg.Count; i++ { bootRequests <- i go func() { for index := range bootRequests { vmCfg, err := config.CreateVMConfig(cfg, index) if err != nil { Fatalf("failed to create VM config: %v", err) } inst, err := vm.Create(cfg.Type, vmCfg) if err != nil { Fatalf("failed to create VM: %v", err) } execprogBin, err := inst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-execprog")) if err != nil { Fatalf("failed to copy to VM: %v", err) } executorBin, err := inst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-executor")) if err != nil { Fatalf("failed to copy to VM: %v", err) } instances <- VM{inst, index, execprogBin, executorBin} } }() } go func() { c := make(chan os.Signal, 2) signal.Notify(c, syscall.SIGINT) <-c close(shutdown) Logf(-1, "shutting down...") <-c Fatalf("terminating") }() repro(cfg, entries, crashStart) exit() }
func MonitorExecution(outc <-chan []byte, errc <-chan error, local, needOutput bool) (desc string, text, output []byte, crashed, timedout bool) { waitForOutput := func() { dur := time.Second if needOutput { dur = 10 * time.Second } timer := time.NewTimer(dur).C for { select { case out, ok := <-outc: if !ok { return } output = append(output, out...) case <-timer: return } } } matchPos := 0 const ( beforeContext = 256 << 10 afterContext = 128 << 10 ) extractError := func(defaultError string) (string, []byte, []byte, bool, bool) { // Give it some time to finish writing the error message. waitForOutput() if !report.ContainsCrash(output[matchPos:]) { return defaultError, nil, output, true, false } desc, text, start, end := report.Parse(output[matchPos:]) start = start + matchPos - beforeContext if start < 0 { start = 0 } end = end + matchPos + afterContext if end > len(output) { end = len(output) } return desc, text, output[start:end], true, false } lastExecuteTime := time.Now() ticker := time.NewTimer(3 * time.Minute) tickerFired := false for { if !tickerFired && !ticker.Stop() { <-ticker.C } tickerFired = false ticker.Reset(3 * time.Minute) select { case err := <-errc: switch err { case nil: waitForOutput() return "", nil, output, false, false case TimeoutErr: return err.Error(), nil, nil, false, true default: // Note: connection lost can race with a kernel oops message. // In such case we want to return the kernel oops. return extractError("lost connection to test machine") } case out := <-outc: output = append(output, out...) if bytes.Index(output[matchPos:], []byte("executing program")) != -1 { // syz-fuzzer output lastExecuteTime = time.Now() } if bytes.Index(output[matchPos:], []byte("executed programs:")) != -1 { // syz-execprog output lastExecuteTime = time.Now() } if report.ContainsCrash(output[matchPos:]) { return extractError("") } if len(output) > 2*beforeContext { copy(output, output[len(output)-beforeContext:]) output = output[:beforeContext] } matchPos = len(output) - 128 if matchPos < 0 { matchPos = 0 } // In some cases kernel constantly prints something to console, // but fuzzer is not actually executing programs. if !local && time.Since(lastExecuteTime) > 3*time.Minute { return "test machine is not executing programs", nil, output, true, false } case <-ticker.C: tickerFired = true if !local { return "no output from test machine", nil, output, true, false } case <-Shutdown: return "", nil, nil, false, false } } }