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