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