// Copyright 2022 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. package proxyapp import ( "context" "encoding/json" "errors" "fmt" "io" "net/url" "os" "time" "github.com/google/syzkaller/pkg/config" "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/vm/vmimpl" ) func makeDefaultParams() *proxyAppParams { return &proxyAppParams{ CommandRunner: osutilCommandContext, InitRetryDelay: 10 * time.Second, LogOutput: os.Stdout, } } func init() { vmimpl.Register("proxyapp", vmimpl.Type{ Ctor: func(env *vmimpl.Env) (vmimpl.Pool, error) { return ctor(makeDefaultParams(), env) }, }) } // Package configuration VARs are mostly needed for tests. type proxyAppParams struct { CommandRunner func(context.Context, string, ...string) subProcessCmd InitRetryDelay time.Duration LogOutput io.Writer } func osutilCommandContext(ctx context.Context, bin string, args ...string) subProcessCmd { return osutil.CommandContext(ctx, bin, args...) } type subProcessCmd interface { StdinPipe() (io.WriteCloser, error) StdoutPipe() (io.ReadCloser, error) StderrPipe() (io.ReadCloser, error) Start() error Wait() error } // Config is valid if at least cmd or rpc_server_uri specified. type Config struct { // cmd is the optional command needed to initialize plugin. // By default we'll connect to its std[in, out, err]. Command string `json:"cmd"` // rpc_server_uri is used to specify plugin endpoint address. // if not specified, we'll connect to the plugin by std[in, out, err]. RPCServerURI string `json:"rpc_server_uri"` // security can be one of "none", "tls" (for server TLS) and "mtls" for mutal // TLS. Security string `json:"security"` // server_tls_cert points a TLS certificate used to authenticate the server. // If not provided, the default system certificate pool will be used. ServerTLSCert string `json:"server_tls_cert"` // transfer_file_content will send the file content as a byte array in // addition to the filename. TransferFileContent bool `json:"transfer_file_content"` // config is an optional remote plugin config ProxyAppConfig json.RawMessage `json:"config"` } func parseConfig(conf []byte) (*Config, error) { vmCfg := new(Config) if err := config.LoadData(conf, vmCfg); err != nil { return nil, fmt.Errorf("failed to parseConfig(): %w", err) } if vmCfg.RPCServerURI == "" && vmCfg.Command == "" { return nil, errors.New("failed to parseConfig(): neither 'cmd' nor 'rpc_server_uri' specified for plugin") } if vmCfg.RPCServerURI != "" && URIParseErr(vmCfg.RPCServerURI) != nil { return nil, fmt.Errorf("failed to parseConfig(): %w", URIParseErr(vmCfg.RPCServerURI)) } return vmCfg, nil } func URIParseErr(uri string) error { dest, err := url.Parse("http://" + uri) if err != nil || dest.Port() == "" || dest.Host != uri { return fmt.Errorf("bad uri (%v), host:port were expected", uri) } return nil }