github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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  	go hub.purgeOldManagers()
    64  
    65  	s, err := rpctype.NewRPCServer(cfg.RPC, "Hub", hub)
    66  	if err != nil {
    67  		log.Fatalf("failed to create rpc server: %v", err)
    68  	}
    69  	log.Logf(0, "serving rpc on tcp://%v", s.Addr())
    70  	s.Serve()
    71  }
    72  
    73  func (hub *Hub) Connect(a *rpctype.HubConnectArgs, r *int) error {
    74  	name, err := hub.checkManager(a.Client, a.Key, a.Manager)
    75  	if err != nil {
    76  		return err
    77  	}
    78  	hub.mu.Lock()
    79  	defer hub.mu.Unlock()
    80  
    81  	log.Logf(0, "connect from %v (%v): domain=%v fresh=%v calls=%v corpus=%v",
    82  		name, a.HTTP, a.Domain, a.Fresh, len(a.Calls), len(a.Corpus))
    83  	if err := hub.st.Connect(name, a.HTTP, a.Domain, a.Fresh, a.Calls, a.Corpus); err != nil {
    84  		log.Logf(0, "connect error: %v", err)
    85  		return err
    86  	}
    87  	return nil
    88  }
    89  
    90  func (hub *Hub) Sync(a *rpctype.HubSyncArgs, r *rpctype.HubSyncRes) error {
    91  	name, err := hub.checkManager(a.Client, a.Key, a.Manager)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	hub.mu.Lock()
    96  	defer hub.mu.Unlock()
    97  
    98  	domain, inputs, more, err := hub.st.Sync(name, a.Add, a.Del)
    99  	if err != nil {
   100  		log.Logf(0, "sync error: %v", err)
   101  		return err
   102  	}
   103  	if domain != "" {
   104  		r.Inputs = inputs
   105  	} else {
   106  		for _, inp := range inputs {
   107  			r.Progs = append(r.Progs, inp.Prog)
   108  		}
   109  	}
   110  	r.More = more
   111  	for _, repro := range a.Repros {
   112  		if err := hub.st.AddRepro(name, repro); err != nil {
   113  			log.Logf(0, "add repro error: %v", err)
   114  		}
   115  	}
   116  	if a.NeedRepros {
   117  		repro, err := hub.st.PendingRepro(name)
   118  		if err != nil {
   119  			log.Logf(0, "sync error: %v", err)
   120  		}
   121  		if repro != nil {
   122  			r.Repros = [][]byte{repro}
   123  		}
   124  	}
   125  	log.Logf(0, "sync from %v: recv: add=%v del=%v repros=%v; send: progs=%v repros=%v pending=%v",
   126  		name, len(a.Add), len(a.Del), len(a.Repros), len(inputs), len(r.Repros), more)
   127  	return nil
   128  }
   129  
   130  func (hub *Hub) purgeOldManagers() {
   131  	for range time.NewTicker(time.Hour).C {
   132  		hub.mu.Lock()
   133  		if err := hub.st.PurgeOldManagers(); err != nil {
   134  			log.Logf(0, "failed to purge managers: %v", err)
   135  		}
   136  		hub.mu.Unlock()
   137  	}
   138  }
   139  
   140  func (hub *Hub) verifyKey(key, expectedKey string) error {
   141  	if strings.HasPrefix(expectedKey, auth.OauthMagic) {
   142  		subj, err := hub.auth.DetermineAuthSubj(time.Now(), []string{key})
   143  		if err != nil {
   144  			return err
   145  		}
   146  		if subj != expectedKey {
   147  			return fmt.Errorf("bad token")
   148  		}
   149  		// Success due to correct token.
   150  		return nil
   151  	}
   152  	if key != expectedKey {
   153  		return fmt.Errorf("bad password")
   154  	}
   155  	// Success due to correct password.
   156  	return nil
   157  }
   158  
   159  // Returns the verified manager identity or error.
   160  func (hub *Hub) checkManager(client, key, manager string) (string, error) {
   161  	expectedKey, ok := hub.keys[client]
   162  	if !ok {
   163  		log.Logf(0, "connect from unauthorized client %v", client)
   164  		return "", fmt.Errorf("unauthorized manager")
   165  	}
   166  	if err := hub.verifyKey(key, expectedKey); err != nil {
   167  		log.Logf(0, "connect from unauthorized client %v", client)
   168  		return "", fmt.Errorf("unauthorized manager")
   169  	}
   170  	if manager == "" {
   171  		manager = client
   172  	} else if !strings.HasPrefix(manager, client) {
   173  		log.Logf(0, "manager %v does not have client prefix %v", manager, client)
   174  		return "", fmt.Errorf("unauthorized manager")
   175  	}
   176  	return manager, nil
   177  }