github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/tools/syz-repro/repro.go (about) 1 // Copyright 2015 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 main 5 6 import ( 7 "flag" 8 "fmt" 9 "os" 10 "path/filepath" 11 12 "github.com/google/syzkaller/pkg/csource" 13 "github.com/google/syzkaller/pkg/flatrpc" 14 "github.com/google/syzkaller/pkg/log" 15 "github.com/google/syzkaller/pkg/mgrconfig" 16 "github.com/google/syzkaller/pkg/osutil" 17 "github.com/google/syzkaller/pkg/report" 18 "github.com/google/syzkaller/pkg/repro" 19 "github.com/google/syzkaller/vm" 20 ) 21 22 var ( 23 flagConfig = flag.String("config", "", "manager configuration file (manager.cfg)") 24 flagCount = flag.Int("count", 0, "number of VMs to use (overrides config count param)") 25 flagDebug = flag.Bool("debug", false, "print debug output") 26 flagOutput = flag.String("output", filepath.Join(".", "repro.txt"), "output syz repro file (repro.txt)") 27 flagCRepro = flag.String("crepro", filepath.Join(".", "repro.c"), "output c file (repro.c)") 28 flagTitle = flag.String("title", "", "where to save the title of the reproduced bug") 29 flagStrace = flag.String("strace", "", "output strace log (strace_bin must be set)") 30 ) 31 32 func main() { 33 os.Args = append(append([]string{}, os.Args[0], "-vv=10"), os.Args[1:]...) 34 flag.Parse() 35 if len(flag.Args()) != 1 || *flagConfig == "" { 36 log.Fatalf("usage: syz-repro -config=manager.cfg execution.log") 37 } 38 cfg, err := mgrconfig.LoadFile(*flagConfig) 39 if err != nil { 40 log.Fatalf("%v: %v", *flagConfig, err) 41 } 42 logFile := flag.Args()[0] 43 data, err := os.ReadFile(logFile) 44 if err != nil { 45 log.Fatalf("failed to open log file %v: %v", logFile, err) 46 } 47 vmPool, err := vm.Create(cfg, *flagDebug) 48 if err != nil { 49 log.Fatalf("%v", err) 50 } 51 vmCount := vmPool.Count() 52 if *flagCount > 0 && *flagCount < vmCount { 53 vmCount = *flagCount 54 } 55 if vmCount > 4 { 56 vmCount = 4 57 } 58 vmIndexes := make([]int, vmCount) 59 for i := range vmIndexes { 60 vmIndexes[i] = i 61 } 62 reporter, err := report.NewReporter(cfg) 63 if err != nil { 64 log.Fatalf("%v", err) 65 } 66 osutil.HandleInterrupts(vm.Shutdown) 67 68 res, stats, err := repro.Run(data, cfg, flatrpc.AllFeatures, reporter, vmPool, vmIndexes) 69 if err != nil { 70 log.Logf(0, "reproduction failed: %v", err) 71 } 72 if stats != nil { 73 fmt.Printf("extracting prog: %v\n", stats.ExtractProgTime) 74 fmt.Printf("minimizing prog: %v\n", stats.MinimizeProgTime) 75 fmt.Printf("simplifying prog options: %v\n", stats.SimplifyProgTime) 76 fmt.Printf("extracting C: %v\n", stats.ExtractCTime) 77 fmt.Printf("simplifying C: %v\n", stats.SimplifyCTime) 78 } 79 if res == nil { 80 return 81 } 82 83 fmt.Printf("opts: %+v crepro: %v\n\n", res.Opts, res.CRepro) 84 85 progSerialized := res.Prog.Serialize() 86 fmt.Printf("%s\n", progSerialized) 87 if err = osutil.WriteFile(*flagOutput, progSerialized); err == nil { 88 fmt.Printf("program saved to %s\n", *flagOutput) 89 } else { 90 log.Logf(0, "failed to write prog to file: %v", err) 91 } 92 93 if res.Report != nil && *flagTitle != "" { 94 recordTitle(res, *flagTitle) 95 } 96 if res.CRepro { 97 recordCRepro(res, *flagCRepro) 98 } 99 if *flagStrace != "" { 100 result := repro.RunStrace(res, cfg, reporter, vmPool, vmIndexes[0]) 101 recordStraceResult(result, *flagStrace) 102 } 103 } 104 105 func recordTitle(res *repro.Result, fileName string) { 106 if err := osutil.WriteFile(fileName, []byte(res.Report.Title)); err == nil { 107 fmt.Printf("bug title saved to %s\n", *flagTitle) 108 } else { 109 log.Logf(0, "failed to write bug title to file: %v", err) 110 } 111 } 112 113 func recordCRepro(res *repro.Result, fileName string) { 114 src, err := csource.Write(res.Prog, res.Opts) 115 if err != nil { 116 log.Fatalf("failed to generate C repro: %v", err) 117 } 118 if formatted, err := csource.Format(src); err == nil { 119 src = formatted 120 } 121 fmt.Printf("%s\n", src) 122 123 if err := osutil.WriteFile(fileName, src); err == nil { 124 fmt.Printf("C file saved to %s\n", *flagCRepro) 125 } else { 126 log.Logf(0, "failed to write C repro to file: %v", err) 127 } 128 } 129 130 func recordStraceResult(result *repro.StraceResult, fileName string) { 131 if result.Error != nil { 132 log.Logf(0, "failed to run strace: %v", result.Error) 133 return 134 } 135 if result.Report != nil { 136 log.Logf(0, "under strace repro crashed with title: %s", result.Report.Title) 137 } else { 138 log.Logf(0, "repro didn't crash under strace") 139 } 140 if err := osutil.WriteFile(fileName, result.Output); err == nil { 141 fmt.Printf("C file saved to %s\n", *flagStrace) 142 } else { 143 log.Logf(0, "failed to write strace output to file: %v", err) 144 } 145 }