github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/vm/proxyapp/init.go (about)

     1  // Copyright 2022 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 proxyapp
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"net/url"
    13  	"os"
    14  	"time"
    15  
    16  	"github.com/google/syzkaller/pkg/config"
    17  	"github.com/google/syzkaller/pkg/osutil"
    18  	"github.com/google/syzkaller/vm/vmimpl"
    19  )
    20  
    21  func makeDefaultParams() *proxyAppParams {
    22  	return &proxyAppParams{
    23  		CommandRunner:  osutilCommandContext,
    24  		InitRetryDelay: 10 * time.Second,
    25  		LogOutput:      os.Stdout,
    26  	}
    27  }
    28  
    29  func init() {
    30  	vmimpl.Register(
    31  		"proxyapp",
    32  		func(env *vmimpl.Env) (vmimpl.Pool, error) {
    33  			return ctor(makeDefaultParams(), env)
    34  		},
    35  		false)
    36  }
    37  
    38  // Package configuration VARs are mostly needed for tests.
    39  type proxyAppParams struct {
    40  	CommandRunner  func(context.Context, string, ...string) subProcessCmd
    41  	InitRetryDelay time.Duration
    42  	LogOutput      io.Writer
    43  }
    44  
    45  func osutilCommandContext(ctx context.Context, bin string, args ...string) subProcessCmd {
    46  	return osutil.CommandContext(ctx, bin, args...)
    47  }
    48  
    49  type subProcessCmd interface {
    50  	StdinPipe() (io.WriteCloser, error)
    51  	StdoutPipe() (io.ReadCloser, error)
    52  	StderrPipe() (io.ReadCloser, error)
    53  	Start() error
    54  	Wait() error
    55  }
    56  
    57  // Config is valid if at least cmd or rpc_server_uri specified.
    58  type Config struct {
    59  	// cmd is the optional command needed to initialize plugin.
    60  	// By default we'll connect to its std[in, out, err].
    61  	Command string `json:"cmd"`
    62  	// rpc_server_uri is used to specify plugin endpoint address.
    63  	// if not specified, we'll connect to the plugin by std[in, out, err].
    64  	RPCServerURI string `json:"rpc_server_uri"`
    65  	// security can be one of "none", "tls" (for server TLS) and "mtls" for mutal
    66  	// TLS.
    67  	Security string `json:"security"`
    68  	// server_tls_cert points a TLS certificate used to authenticate the server.
    69  	// If not provided, the default system certificate pool will be used.
    70  	ServerTLSCert string `json:"server_tls_cert"`
    71  	// transfer_file_content will send the file content as a byte array in
    72  	// addition to the filename.
    73  	TransferFileContent bool `json:"transfer_file_content"`
    74  	// config is an optional remote plugin config
    75  	ProxyAppConfig json.RawMessage `json:"config"`
    76  }
    77  
    78  func parseConfig(conf []byte) (*Config, error) {
    79  	vmCfg := new(Config)
    80  	if err := config.LoadData(conf, vmCfg); err != nil {
    81  		return nil, fmt.Errorf("failed to parseConfig(): %w", err)
    82  	}
    83  
    84  	if vmCfg.RPCServerURI == "" && vmCfg.Command == "" {
    85  		return nil, errors.New("failed to parseConfig(): neither 'cmd' nor 'rpc_server_uri' specified for plugin")
    86  	}
    87  
    88  	if vmCfg.RPCServerURI != "" && URIParseErr(vmCfg.RPCServerURI) != nil {
    89  		return nil, fmt.Errorf("failed to parseConfig(): %w", URIParseErr(vmCfg.RPCServerURI))
    90  	}
    91  
    92  	return vmCfg, nil
    93  }
    94  
    95  func URIParseErr(uri string) error {
    96  	dest, err := url.Parse("http://" + uri)
    97  	if err != nil || dest.Port() == "" || dest.Host != uri {
    98  		return fmt.Errorf("bad uri (%v), host:port were expected", uri)
    99  	}
   100  	return nil
   101  }