github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/tools/syz-hubtool/hubtool.go (about)

     1  // Copyright 2020 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  // syz-hubtool uploads local reproducers to syz-hub.
     5  package main
     6  
     7  import (
     8  	"flag"
     9  	"log"
    10  	"net/http"
    11  	"os"
    12  	"path/filepath"
    13  	"runtime"
    14  	"time"
    15  
    16  	"github.com/google/syzkaller/pkg/auth"
    17  	"github.com/google/syzkaller/pkg/db"
    18  	"github.com/google/syzkaller/pkg/rpctype"
    19  	"github.com/google/syzkaller/prog"
    20  	_ "github.com/google/syzkaller/sys"
    21  )
    22  
    23  func main() {
    24  	var (
    25  		flagOS          = flag.String("os", runtime.GOOS, "target OS")
    26  		flagArch        = flag.String("arch", runtime.GOARCH, "target Arch")
    27  		flagHubAddress  = flag.String("addr", "", "hub address")
    28  		flagHubClient   = flag.String("client", "", "hub API client")
    29  		flagHubKey      = flag.String("key", "", "hub API key")
    30  		flagHubManager  = flag.String("manager", "", "manager name to upload on behalf of")
    31  		flagRepro       = flag.String("repro", "", "reproducer glob pattern to upload")
    32  		flagCorpus      = flag.String("corpus", "", "coprpus file to upload")
    33  		flagCorpusProgs = flag.String("corpus_progs", "", "a glob pattern of progs to add to corpus")
    34  		flagWorkdir     = flag.String("workdir", "", "workdir to upload coprpus and reproducers")
    35  		flagDrain       = flag.Bool("drain", false, "drain hub corpus and reproducers for the given manager")
    36  	)
    37  	flag.Parse()
    38  	target, err := prog.GetTarget(*flagOS, *flagArch)
    39  	if err != nil {
    40  		log.Fatal(err)
    41  	}
    42  	if *flagWorkdir != "" {
    43  		*flagRepro = filepath.Join(*flagWorkdir, "crashes", "*", "repro.prog")
    44  		*flagCorpus = filepath.Join(*flagWorkdir, "corpus.db")
    45  	}
    46  	var repros, corpus [][]byte
    47  	if *flagRepro != "" {
    48  		repros = loadProgs(target, *flagRepro)
    49  	}
    50  	if *flagCorpus != "" {
    51  		corpus = loadCorpus(target, *flagCorpus)
    52  	} else if *flagCorpusProgs != "" {
    53  		corpus = loadProgs(target, *flagCorpusProgs)
    54  	}
    55  	log.Printf("loaded %v reproducers, %v corpus programs", len(repros), len(corpus))
    56  	if len(repros)+len(corpus) == 0 && !*flagDrain {
    57  		return
    58  	}
    59  	log.Printf("connecting to hub at %v...", *flagHubAddress)
    60  	conn, err := rpctype.NewRPCClient(*flagHubAddress)
    61  	if err != nil {
    62  		log.Fatalf("failed to connect to hub: %v", err)
    63  	}
    64  	key := *flagHubKey
    65  	if *flagHubKey == "" {
    66  		tokenCache, err := auth.MakeCache(http.NewRequest, http.DefaultClient.Do)
    67  		if err != nil {
    68  			log.Fatalf("failed to make auth cache %v", err)
    69  		}
    70  		key, err = tokenCache.Get(time.Now())
    71  		if err != nil {
    72  			log.Fatalf("failed to get a token %v", err)
    73  		}
    74  	}
    75  	connectArgs := &rpctype.HubConnectArgs{
    76  		Client:  *flagHubClient,
    77  		Key:     key,
    78  		Manager: *flagHubManager,
    79  		Fresh:   false,
    80  		Calls:   nil,
    81  		Corpus:  corpus,
    82  	}
    83  	if err := conn.Call("Hub.Connect", connectArgs, nil); err != nil {
    84  		log.Fatalf("Hub.Connect failed: %v", err)
    85  	}
    86  	log.Printf("uploaded %v corpus programs", len(corpus))
    87  	if len(repros) != 0 {
    88  		syncArgs := &rpctype.HubSyncArgs{
    89  			Client:  *flagHubClient,
    90  			Key:     key,
    91  			Manager: *flagHubManager,
    92  			Repros:  repros,
    93  		}
    94  		if err := conn.Call("Hub.Sync", syncArgs, new(rpctype.HubSyncRes)); err != nil {
    95  			log.Fatalf("Hub.Sync failed: %v", err)
    96  		}
    97  		log.Printf("uploaded %v reproducers", len(repros))
    98  	}
    99  	for *flagDrain {
   100  		syncArgs := &rpctype.HubSyncArgs{
   101  			Client:     *flagHubClient,
   102  			Key:        key,
   103  			Manager:    *flagHubManager,
   104  			NeedRepros: true,
   105  		}
   106  		resp := new(rpctype.HubSyncRes)
   107  		if err := conn.Call("Hub.Sync", syncArgs, resp); err != nil {
   108  			log.Fatalf("Hub.Sync failed: %v", err)
   109  		}
   110  		log.Printf("received %v progs, %v repros, %v more", len(resp.Progs), len(resp.Repros), resp.More)
   111  		if len(resp.Progs)+len(resp.Repros) == 0 {
   112  			break
   113  		}
   114  	}
   115  }
   116  
   117  func loadProgs(target *prog.Target, reproGlob string) [][]byte {
   118  	files, err := filepath.Glob(reproGlob)
   119  	if err != nil {
   120  		log.Fatal(err)
   121  	}
   122  	var repros [][]byte
   123  	dedup := make(map[string]bool)
   124  	for _, file := range files {
   125  		data, err := os.ReadFile(file)
   126  		if err != nil {
   127  			log.Fatal(err)
   128  		}
   129  		if _, err := target.Deserialize(data, prog.NonStrict); err != nil {
   130  			log.Printf("failed to deserialize %v: %v", file, err)
   131  			continue
   132  		}
   133  		if dedup[string(data)] {
   134  			log.Printf("%v is a duplicate", file)
   135  			continue
   136  		}
   137  		dedup[string(data)] = true
   138  		repros = append(repros, data)
   139  	}
   140  	return repros
   141  }
   142  
   143  func loadCorpus(target *prog.Target, corpusDB string) [][]byte {
   144  	progs, err := db.ReadCorpus(corpusDB, target)
   145  	if err != nil {
   146  		log.Fatal(err)
   147  	}
   148  	var corpus [][]byte
   149  	for _, p := range progs {
   150  		corpus = append(corpus, p.Serialize())
   151  	}
   152  	return corpus
   153  }