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

     1  // Copyright 2016 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  	"strings"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/google/syzkaller/pkg/auth"
    14  	"github.com/google/syzkaller/pkg/config"
    15  	"github.com/google/syzkaller/pkg/log"
    16  	"github.com/google/syzkaller/pkg/rpctype"
    17  	"github.com/google/syzkaller/syz-hub/state"
    18  )
    19  
    20  var (
    21  	flagConfig = flag.String("config", "", "config file")
    22  )
    23  
    24  type Config struct {
    25  	HTTP    string
    26  	RPC     string
    27  	Workdir string
    28  	Clients []struct {
    29  		Name string
    30  		Key  string
    31  	}
    32  }
    33  
    34  type Hub struct {
    35  	mu   sync.Mutex
    36  	st   *state.State
    37  	keys map[string]string
    38  	auth auth.Endpoint
    39  }
    40  
    41  func main() {
    42  	flag.Parse()
    43  	cfg := new(Config)
    44  	if err := config.LoadFile(*flagConfig, cfg); err != nil {
    45  		log.Fatal(err)
    46  	}
    47  	log.EnableLogCaching(1000, 1<<20)
    48  
    49  	st, err := state.Make(cfg.Workdir)
    50  	if err != nil {
    51  		log.Fatalf("failed to load state: %v", err)
    52  	}
    53  	hub := &Hub{
    54  		st:   st,
    55  		keys: make(map[string]string),
    56  		auth: auth.MakeEndpoint(auth.GoogleTokenInfoEndpoint),
    57  	}
    58  	for _, mgr := range cfg.Clients {
    59  		hub.keys[mgr.Name] = mgr.Key
    60  	}
    61  
    62  	hub.initHTTP(cfg.HTTP)
    63  
    64  	s, err := rpctype.NewRPCServer(cfg.RPC, "Hub", hub)
    65  	if err != nil {
    66  		log.Fatalf("failed to create rpc server: %v", err)
    67  	}
    68  	log.Logf(0, "serving rpc on tcp://%v", s.Addr())
    69  	s.Serve()
    70  }
    71  
    72  func (hub *Hub) Connect(a *rpctype.HubConnectArgs, r *int) error {
    73  	name, err := hub.checkManager(a.Client, a.Key, a.Manager)
    74  	if err != nil {
    75  		return err
    76  	}
    77  	hub.mu.Lock()
    78  	defer hub.mu.Unlock()
    79  
    80  	log.Logf(0, "connect from %v: domain=%v fresh=%v calls=%v corpus=%v",
    81  		name, a.Domain, a.Fresh, len(a.Calls), len(a.Corpus))
    82  	if err := hub.st.Connect(name, a.Domain, a.Fresh, a.Calls, a.Corpus); err != nil {
    83  		log.Logf(0, "connect error: %v", err)
    84  		return err
    85  	}
    86  	return nil
    87  }
    88  
    89  func (hub *Hub) Sync(a *rpctype.HubSyncArgs, r *rpctype.HubSyncRes) error {
    90  	name, err := hub.checkManager(a.Client, a.Key, a.Manager)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	hub.mu.Lock()
    95  	defer hub.mu.Unlock()
    96  
    97  	domain, inputs, more, err := hub.st.Sync(name, a.Add, a.Del)
    98  	if err != nil {
    99  		log.Logf(0, "sync error: %v", err)
   100  		return err
   101  	}
   102  	if domain != "" {
   103  		r.Inputs = inputs
   104  	} else {
   105  		for _, inp := range inputs {
   106  			r.Progs = append(r.Progs, inp.Prog)
   107  		}
   108  	}
   109  	r.More = more
   110  	for _, repro := range a.Repros {
   111  		if err := hub.st.AddRepro(name, repro); err != nil {
   112  			log.Logf(0, "add repro error: %v", err)
   113  		}
   114  	}
   115  	if a.NeedRepros {
   116  		repro, err := hub.st.PendingRepro(name)
   117  		if err != nil {
   118  			log.Logf(0, "sync error: %v", err)
   119  		}
   120  		if repro != nil {
   121  			r.Repros = [][]byte{repro}
   122  		}
   123  	}
   124  	log.Logf(0, "sync from %v: recv: add=%v del=%v repros=%v; send: progs=%v repros=%v pending=%v",
   125  		name, len(a.Add), len(a.Del), len(a.Repros), len(inputs), len(r.Repros), more)
   126  	return nil
   127  }
   128  
   129  func (hub *Hub) verifyKey(key, expectedKey string) error {
   130  	if strings.HasPrefix(expectedKey, auth.OauthMagic) {
   131  		subj, err := hub.auth.DetermineAuthSubj(time.Now(), []string{key})
   132  		if err != nil {
   133  			return err
   134  		}
   135  		if subj != expectedKey {
   136  			return fmt.Errorf("bad token")
   137  		}
   138  		// Success due to correct token.
   139  		return nil
   140  	}
   141  	if key != expectedKey {
   142  		return fmt.Errorf("bad password")
   143  	}
   144  	// Success due to correct password.
   145  	return nil
   146  }
   147  
   148  // Returns the verified manager identity or error.
   149  func (hub *Hub) checkManager(client, key, manager string) (string, error) {
   150  	expectedKey, ok := hub.keys[client]
   151  	if !ok {
   152  		log.Logf(0, "connect from unauthorized client %v", client)
   153  		return "", fmt.Errorf("unauthorized manager")
   154  	}
   155  	if err := hub.verifyKey(key, expectedKey); err != nil {
   156  		log.Logf(0, "connect from unauthorized client %v", client)
   157  		return "", fmt.Errorf("unauthorized manager")
   158  	}
   159  	if manager == "" {
   160  		manager = client
   161  	} else if !strings.HasPrefix(manager, client) {
   162  		log.Logf(0, "manager %v does not have client prefix %v", manager, client)
   163  		return "", fmt.Errorf("unauthorized manager")
   164  	}
   165  	return manager, nil
   166  }