aboutsummaryrefslogtreecommitdiff
path: root/tools/syz-reprolist/reprolist.go
diff options
context:
space:
mode:
Diffstat (limited to 'tools/syz-reprolist/reprolist.go')
-rw-r--r--tools/syz-reprolist/reprolist.go233
1 files changed, 233 insertions, 0 deletions
diff --git a/tools/syz-reprolist/reprolist.go b/tools/syz-reprolist/reprolist.go
new file mode 100644
index 000000000..5d082b37e
--- /dev/null
+++ b/tools/syz-reprolist/reprolist.go
@@ -0,0 +1,233 @@
+// Copyright 2019 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.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/google/syzkaller/dashboard/dashapi"
+ "github.com/google/syzkaller/pkg/csource"
+ "github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/pkg/vcs"
+)
+
+var (
+ flagDashboard = flag.String("dashboard", "https://syzkaller.appspot.com", "dashboard address")
+ flagAPIClient = flag.String("client", "", "api client")
+ flagAPIKey = flag.String("key", "", "api key")
+ flagOutputDir = flag.String("output", "repros", "output dir")
+ flagSyzkallerDir = flag.String("syzkaller", ".", "syzkaller dir")
+ flagOS = flag.String("os", runtime.GOOS, "target OS")
+)
+
+func main() {
+ flag.Parse()
+ if *flagAPIClient == "" || *flagAPIKey == "" {
+ log.Fatalf("api client and key are required")
+ }
+ if err := os.MkdirAll(*flagOutputDir, 0755); err != nil {
+ log.Fatalf("failed to create output dir: %v", err)
+ }
+ dash := dashapi.New(*flagAPIClient, *flagDashboard, *flagAPIKey)
+ resp, err := dash.BugList()
+ if err != nil {
+ log.Fatalf("api call failed: %v", err)
+ }
+ log.Printf("loading %v bugs", len(resp.List))
+ const P = 10
+ idchan := make(chan string, 10*P)
+ bugchan := make(chan *dashapi.LoadBugResp, 10*P)
+ go func() {
+ for _, id := range resp.List {
+ if _, err := os.Stat(filepath.Join(*flagOutputDir, id+".c")); err == nil {
+ log.Printf("%v: already present", id)
+ continue
+ }
+ if _, err := os.Stat(filepath.Join(*flagOutputDir, id+".norepro")); err == nil {
+ log.Printf("%v: no repro (cached)", id)
+ continue
+ }
+ idchan <- id
+ }
+ close(idchan)
+ }()
+ var wg sync.WaitGroup
+ wg.Add(P)
+ for p := 0; p < P; p++ {
+ go func() {
+ defer wg.Done()
+ for id := range idchan {
+ resp, err := dash.LoadBug(id)
+ if err != nil {
+ log.Printf("%v: failed to load bug: %v", id, err)
+ continue
+ }
+ if resp.ID == "" {
+ continue
+ }
+ bugchan <- resp
+ }
+ }()
+ }
+ go func() {
+ wg.Wait()
+ close(bugchan)
+ }()
+ writeRepros(bugchan)
+}
+
+func writeRepros(bugchan chan *dashapi.LoadBugResp) {
+ for bug := range bugchan {
+ if len(bug.ReproSyz) == 0 {
+ log.Printf("%v: %v: no repro", bug.ID, bug.Status)
+ file := filepath.Join(*flagOutputDir, bug.ID+".norepro")
+ if err := ioutil.WriteFile(file, nil, 0644); err != nil {
+ log.Fatalf("failed to write file: %v", err)
+ }
+ continue
+ }
+ if len(bug.ReproC) == 0 {
+ log.Printf("%v: %v: syz repro on %v", bug.ID, bug.Status, bug.SyzkallerCommit)
+ if err := createCRepro(bug); err != nil {
+ log.Print(err)
+ continue
+ }
+ }
+ log.Printf("%v: %v: C repro", bug.ID, bug.Status)
+ arch := ""
+ if bug.Arch != "" && bug.Arch != "amd64" {
+ arch = fmt.Sprintf(" arch:%v", bug.Arch)
+ }
+ repro := []byte(fmt.Sprintf("// %v\n// %v/bug?id=%v\n// status:%v%v\n",
+ bug.Title, *flagDashboard, bug.ID, bug.Status, arch))
+ repro = append(repro, bug.ReproC...)
+ file := filepath.Join(*flagOutputDir, bug.ID+".c")
+ if err := ioutil.WriteFile(file, repro, 0644); err != nil {
+ log.Fatalf("failed to write file: %v", err)
+ }
+ }
+}
+
+func createCRepro(bug *dashapi.LoadBugResp) error {
+ opts, err := csource.DeserializeOptions(bug.ReproOpts)
+ if err != nil {
+ return fmt.Errorf("failed to deserialize opts: %v", err)
+ }
+ file := filepath.Join(*flagOutputDir, bug.ID+".syz")
+ if err := ioutil.WriteFile(file, bug.ReproSyz, 0644); err != nil {
+ return fmt.Errorf("failed to write file: %v", err)
+ }
+ repo := vcs.NewSyzkallerRepo(*flagSyzkallerDir)
+ if _, err := repo.SwitchCommit(bug.SyzkallerCommit); err != nil {
+ return fmt.Errorf("failed to checkout commit %v: %v", bug.SyzkallerCommit, err)
+ }
+ if _, err := osutil.RunCmd(time.Hour, *flagSyzkallerDir, "make", "prog2c"); err != nil {
+ return err
+ }
+ bin := filepath.Join(*flagSyzkallerDir, "bin", "syz-prog2c")
+ args := createProg2CArgs(bug, opts, file)
+ output, err := osutil.RunCmd(time.Hour, "", bin, args...)
+ if err != nil {
+ return err
+ }
+ bug.ReproC = output
+ return err
+}
+
+func createProg2CArgs(bug *dashapi.LoadBugResp, opts csource.Options, file string) []string {
+ haveEnableFlag := containsCommit("dfd609eca1871f01757d6b04b19fc273c87c14e5")
+ haveRepeatFlag := containsCommit("b25fc7b83119e8dca728a199fd92e24dd4c33fa4")
+ haveCgroupFlag := containsCommit("9753d3be5e6c79e271ed128795039f161ee339b7")
+ haveWaitRepeatFlag := containsCommit("c99b02d2248fbdcd6f44037326b16c928f4423f1")
+ haveWaitRepeatRemoved := containsCommit("9fe4bdc5f1037a409e82299f36117030114c7b94")
+ haveCloseFds := containsCommit("5c51045d28eb1ad9465a51487d436133ce7b98d2")
+ haveOSFlag := containsCommit("aa2533b98d21ebcad5777310215159127bfe3573")
+ args := []string{
+ "-prog", file,
+ "-sandbox", opts.Sandbox,
+ fmt.Sprintf("-segv=%v", opts.HandleSegv),
+ fmt.Sprintf("-collide=%v", opts.Collide),
+ fmt.Sprintf("-threaded=%v", opts.Threaded),
+ }
+ if haveOSFlag {
+ args = append(args, "-os", *flagOS)
+ }
+ if bug.Arch != "" && bug.Arch != "amd64" {
+ args = append(args, "-arch", bug.Arch)
+ }
+ if opts.Fault {
+ args = append(args, []string{
+ fmt.Sprintf("-fault_call=%v", opts.FaultCall),
+ fmt.Sprintf("-fault_nth=%v", opts.FaultNth),
+ }...)
+ }
+ if opts.Repeat {
+ if haveRepeatFlag {
+ args = append(args, fmt.Sprintf("-repeat=%v", opts.RepeatTimes))
+ } else {
+ args = append(args, "-repeat")
+ }
+ }
+ if opts.Procs > 0 {
+ args = append(args, fmt.Sprintf("-procs=%v", opts.Procs))
+ }
+ if opts.UseTmpDir {
+ args = append(args, "-tmpdir")
+ }
+ if opts.Leak {
+ args = append(args, "-leak")
+ }
+ var enable, flags []string
+ if opts.EnableTun {
+ enable = append(enable, "tun")
+ flags = append(flags, "-tun")
+ }
+ if opts.EnableNetDev {
+ enable = append(enable, "net_dev")
+ flags = append(flags, "-netdev")
+ }
+ if opts.EnableNetReset {
+ enable = append(enable, "net_reset")
+ flags = append(flags, "-resetnet")
+ }
+ if opts.EnableCgroups {
+ enable = append(enable, "cgroups")
+ if haveCgroupFlag {
+ flags = append(flags, "-cgroups")
+ if haveWaitRepeatFlag && !haveWaitRepeatRemoved {
+ flags = append(flags, "-waitrepeat")
+ }
+ }
+ }
+ if opts.EnableBinfmtMisc {
+ enable = append(enable, "binfmt_misc")
+ }
+ if opts.EnableCloseFds && haveCloseFds {
+ enable = append(enable, "close_fds")
+ }
+ if opts.EnableDevlinkPCI {
+ enable = append(enable, "devlink_pci")
+ flags = append(flags, "-devlinkpci")
+ }
+ if !haveEnableFlag {
+ args = append(args, flags...)
+ } else if len(enable) != 0 {
+ args = append(args, "-enable", strings.Join(enable, ","))
+ }
+ return args
+}
+
+func containsCommit(hash string) bool {
+ _, err := osutil.RunCmd(time.Hour, *flagSyzkallerDir, "git", "merge-base", "--is-ancestor", hash, "HEAD")
+ return err == nil
+}