fuzz

package
v0.0.0-...-bbc9ce3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 6, 2021 License: BSD-2-Clause Imports: 32 Imported by: 0

Documentation

Index

Constants

View Source
const (
	VersionMajor = 0
	VersionMinor = 1
	VersionPatch = 0
)

API version

View Source
const (
	StartInstance = "start_instance"
	StopInstance  = "stop_instance"
	ListFuzzers   = "list_fuzzers"
	PrepareFuzzer = "prepare_fuzzer"
	GetLogs       = "get_logs"
	RunFuzzer     = "run_fuzzer"
	GetData       = "get_data"
	PutData       = "put_data"
	Version       = "version"
)

Available subcommand names

View Source
const (
	FakeQemuNormal  = "qemu-system-x86_64"
	FakeQemuFailing = "failing-qemu"
	FakeQemuSlow    = "slow-qemu"
)

Variables

View Source
var Archs = map[string]struct {
	Binary string
	Kernel string
}{
	"x64":   {"qemu-system-x86_64", "multiboot.bin"},
	"arm64": {"qemu-system-aarch64", "qemu-boot-shim.bin"},
}
View Source
var ExecCommand = exec.Command

ExecCommand is the function used by CreateProcess to create Cmd objects. Test code can replace the default to mock process creation.

This is stubbed out to allow for test code to replace it

View Source
var Platforms = map[string]string{
	"linux":  "linux",
	"darwin": "mac",
}

Functions

func CreateProcess

func CreateProcess(name string, args ...string) error

Run a command to completion

func CreateProcessForeground

func CreateProcessForeground(name string, args ...string) error

CreateProcessForeground is like CreateProcess but passes through any command output

func NewCommand

func NewCommand(name string, args ...string) *exec.Cmd

NewCommand returns a Cmd that can be used to start a new os.Process by calling Run or Start. It is provided to allow the test code to mock process creation.

Types

type APICommand

type APICommand struct {
	// contains filtered or unexported fields
}

An APICommand is the structured result of parsing the command-line args

func ParseArgs

func ParseArgs(args []string) (*APICommand, error)

ParseArgs converts command-line args into an API-command

func (*APICommand) Execute

func (c *APICommand) Execute(out io.Writer) error

Execute the APICommand, writing any output to the given io.Writer

type BaseBuild

type BaseBuild struct {
	Fuzzers map[string]*Fuzzer
	Paths   map[string]string
	IDs     []string
}

BaseBuild is a simple implementation of the Build interface

func (*BaseBuild) Fuzzer

func (b *BaseBuild) Fuzzer(name string) (*Fuzzer, error)

Fuzzer finds the Fuzzer with the given name, if available

func (*BaseBuild) ListFuzzers

func (b *BaseBuild) ListFuzzers() []string

ListFuzzers lists the names of fuzzers present in the build TODO(fxbug.dev/45108): handle variant stripping

func (*BaseBuild) LoadFuzzers

func (b *BaseBuild) LoadFuzzers() error

LoadFuzzers reads and parses fuzzers.json to populate the build's map of Fuzzers. Unless an error is returned, any previously loaded fuzzers will be discarded.

func (*BaseBuild) Path

func (b *BaseBuild) Path(keys ...string) ([]string, error)

Path returns the absolute paths to the list of files indicated by keys. This allows callers to abstract away the detail of where specific file resources are.

func (*BaseBuild) Prepare

func (b *BaseBuild) Prepare() error

Prepare is a no-op for simple builds

func (*BaseBuild) Symbolize

func (b *BaseBuild) Symbolize(in io.Reader, out io.Writer) error

Symbolize reads from in and replaces symbolizer markup with debug information before writing the result to out. This is blocking, and does not propagate EOFs from in to out.

type BaseInstance

type BaseInstance struct {
	Build     Build
	Connector Connector
	Launcher  Launcher
	// contains filtered or unexported fields
}

BaseInstance groups the core subobjects, to which most work will be delegated

func (*BaseInstance) Close

func (i *BaseInstance) Close()

Close releases the Instance, but doesn't Stop it

func (*BaseInstance) Get

func (i *BaseInstance) Get(fuzzerName, targetSrc, hostDst string) error

Get copies files from a fuzzer namespace on the Instance to the host

func (*BaseInstance) GetLogs

func (i *BaseInstance) GetLogs(out io.Writer) error

GetLogs writes any system logs for an instance to `out`

func (*BaseInstance) Handle

func (i *BaseInstance) Handle() (Handle, error)

Handle returns a Handle representing the Instance

func (*BaseInstance) ListFuzzers

func (i *BaseInstance) ListFuzzers() []string

ListFuzzers lists fuzzers available on the Instance

func (*BaseInstance) PrepareFuzzer

func (i *BaseInstance) PrepareFuzzer(name string) error

PrepareFuzzer ensures the named fuzzer is ready to be used on the Instance. This must be called before running the fuzzer or exchanging any data with the fuzzer. If called for a fuzzer that has already been previously prepared, it will reset the state of that fuzzer: clearing data directories, etc.

This method is explicitly separated from RunFuzzer and others to ensure that any caller timeouts being enforced on fuzzer command execution are not affected by unrelated setup delays such as package fetching over the network.

func (*BaseInstance) Put

func (i *BaseInstance) Put(fuzzerName, hostSrc, targetDst string) error

Put copies files from the host to a fuzzer namespace on the Instance

func (*BaseInstance) RunFuzzer

func (i *BaseInstance) RunFuzzer(out io.Writer, name, hostArtifactDir string, args ...string) error

RunFuzzer runs the named fuzzer on the Instance. If `hostArtifactDir` is specified and the run generated any output artifacts, they will be copied to that directory. `args` is an optional list of arguments in the form `-key=value` that will be passed to libFuzzer.

func (*BaseInstance) Start

func (i *BaseInstance) Start() error

Start boots up the instance and waits for connectivity to be established

If Start succeeds, it is up to the caller to clean up by calling Stop later. However, if it fails, any resources will have been automatically released.

func (*BaseInstance) Stop

func (i *BaseInstance) Stop() error

Stop shuts down the Instance

type Build

type Build interface {
	// Ensures all the needed resources are present and fetches any that are
	// missing. Multiple calls to Prepare should be idempotent for the same
	// Build.
	Prepare() error

	// Returns a fuzzer specified by a `package/binary` name, or an error if it
	// isn't found.
	Fuzzer(name string) (*Fuzzer, error)

	// Returns the absolute host paths for each key.  Each key corresponds to a
	// specific resource provided by the Build.  This abstraction allows for
	// different build types to have different structures.
	Path(keys ...string) ([]string, error)

	// Reads input from `in`, symbolizes it, and writes it back to `out`.
	// Returns on error, or when `in` has no more data to read.  Processing
	// will be streamed, line-by-line.
	// TODO(fxbug.dev/47482): does this belong elsewhere?
	Symbolize(in io.Reader, out io.Writer) error

	// Returns a list of the names of the fuzzers that are available to run
	ListFuzzers() []string
}

A Build represents a Fuchsia build, consisting of all the resources needed to run a fuzzer on an instance (e.g. a Fuchsia image, fuzzer packages and metadata, binary symbols, support utilities, etc.).

func NewBuildFromEnvironment

func NewBuildFromEnvironment() (Build, error)

Attempt to auto-detect the correct Build type

func NewClusterFuzzLegacyBuild

func NewClusterFuzzLegacyBuild() (Build, error)

NewClusterFuzzLegacyBuild will create a BaseBuild with path layouts corresponding to the legacy build bundles used by ClusterFuzz's original Python integration. Note that these build bundles only support x64.

func NewLocalFuchsiaBuild

func NewLocalFuchsiaBuild() (Build, error)

NewLocalFuchsiaBuild will create a BaseBuild with path layouts corresponding to a local Fuchsia checkout

type Connector

type Connector interface {
	// Connect establishes all necessary connections to the instance. It does
	// not need to be explicitly called, because the other Connector methods will
	// automatically connect if necessary, but may be called during initializiation.
	// It the connector is already connected, an error will be returned.
	Connect() error

	// Close closes any open connections to the instance. It is the client's
	// responsibility to call Close() when cleaning up the Connector.
	Close()

	// Returns an InstanceCmd representing the command to be run on the instance. Only one
	// command should be active at a time.
	// TODO(fxbug.dev/47479): In some cases, we should be able to relax the above restriction
	Command(name string, args ...string) InstanceCmd

	// Copies targetSrc (may include globs) to hostDst, which is always assumed
	// to be a directory. Directories are copied recursively.
	Get(targetSrc, hostDst string) error

	// Copies hostSrc (may include globs) to targetDst, which is always assumed
	// to be a directory. Directories are copied recursively.
	Put(hostSrc, targetDst string) error

	// Retrieves a syslog from the instance, filtered to the given process ID
	GetSysLog(pid int) (string, error)
}

A Connector is used to communicate with an instance

type Fuzzer

type Fuzzer struct {

	// Name is `package/binary`
	Name string
	// contains filtered or unexported fields
}

A Fuzzer represents a fuzzer present on an instance.

func NewFuzzer

func NewFuzzer(build Build, pkg, fuzzer string) *Fuzzer

NewFuzzer constructs a fuzzer object with the given pkg/fuzzer name

func (*Fuzzer) AbsPath

func (f *Fuzzer) AbsPath(relpath string) string

AbsPath returns the absolute target path for a given relative path in a fuzzer package. The path may differ depending on whether it is identified as a resource, data, or neither.

func (*Fuzzer) Parse

func (f *Fuzzer) Parse(args []string)

Parse command line arguments for the fuzzer. For '-key=val' style options, the last 'val' for a given 'key' is used.

func (*Fuzzer) Prepare

func (f *Fuzzer) Prepare(conn Connector) error

PrepareFuzzer ensures the named fuzzer is ready to be used on the Instance. This must be called before running the fuzzer or exchanging any data with the fuzzer.

func (*Fuzzer) Run

func (f *Fuzzer) Run(conn Connector, out io.Writer, hostArtifactDir string) ([]string, error)

Run the fuzzer, sending symbolized output to `out` and returning a list of any referenced artifacts (e.g. crashes) as absolute paths. If provided, `hostArtifactDir` will be used to transparently rewrite artifact_prefix references in artifact paths in the output log.

type Handle

type Handle string

func LoadHandleFromString

func LoadHandleFromString(s string) (Handle, error)

LoadHandleFromString recreates a previously-created Handle from its string representation as returned by Serialize()

func NewHandle

func NewHandle() (Handle, error)

NewHandle allocates a new handle for use. It will persist until explicitly Released.

func NewHandleWithData

func NewHandleWithData(initialData HandleData) (Handle, error)

NewHandleWithData is a convenience function for populating a new Handle at the same time as creating it.

func (Handle) GetData

func (h Handle) GetData() (*HandleData, error)

GetData will load and return data from the Handle, as previously stored by SetData.

func (Handle) Release

func (h Handle) Release()

Release removes any resources used by the Handle. After calling Release, the handle will become invalid and cannot be further used.

func (Handle) Serialize

func (h Handle) Serialize() string

Serialize returns a printable representation of the Handle

func (Handle) SetData

func (h Handle) SetData(data HandleData) error

SetData stores all exported fields of the given data into the Handle, so they can later be retrieved with GetData. Any existing data in the Handle will be overwritten.

type HandleData

type HandleData struct {
	// contains filtered or unexported fields
}

HandleData represents the top-level structure of the data stored within the Handle.

type Instance

type Instance interface {
	Start() error
	Stop() error
	ListFuzzers() []string
	Get(fuzzerName, targetSrc, hostDst string) error
	Put(fuzzerName, hostSrc, targetDst string) error
	RunFuzzer(out io.Writer, name, hostArtifactDir string, args ...string) error
	GetLogs(out io.Writer) error
	PrepareFuzzer(name string) error
	Handle() (Handle, error)
	Close()
}

An Instance is a specific combination of build, connector, and launcher, representable by a handle. Most methods of this interface map directly to the ClusterFuchsia API.

func NewInstance

func NewInstance() (Instance, error)

NewInstance creates a fresh instance

type InstanceCmd

type InstanceCmd interface {
	// Output runs the command and returns its combined output.
	Output() ([]byte, error)

	// Runs the specified command and waits for it to complete.
	//
	// The returned error is nil if the command runs, has no problems copying
	// input and output, and exits with a zero exit status.
	Run() error

	// Start starts the specified command but does not wait for it to complete.
	Start() error

	// StdinPipe returns a pipe that will be connected to the command's input
	// when the command starts. The pipe will be closed automatically after
	// Wait sees the command exit. A caller need only call Close to force the
	// pipe to close sooner. For example, if the command being run will not
	// exit until the input is closed, the caller must close the pipe.
	StdinPipe() (io.WriteCloser, error)

	// StdoutPipe returns a pipe that will be connected to the command's output
	// when the command starts.
	//
	// Wait will close the pipe after seeing the command exit, so most callers
	// need not close the pipe themselves; however, an implication is that it
	// is incorrect to call Wait before all reads from the pipe have completed.
	// For the same reason, it is incorrect to call Run when using StdoutPipe.
	StdoutPipe() (io.ReadCloser, error)

	// Wait waits for the command to exit and waits for any copying
	// to input or from output to complete.
	//
	// The command must have been started by Start.
	//
	// The returned error is nil if the command runs, has no problems
	// copying input and output, and exits with a zero exit status
	// before any timeout set with SetTimeout is triggered.
	//
	// Wait releases any resources associated with the InstanceCmd.
	Wait() error

	// SetTimeout sets a timeout that will be used for all blocking
	// methods. If a method takes longer than the timeout duration to
	// complete, it will return early with an error.  If not set, or
	// set to 0, methods will block forever.
	SetTimeout(duration time.Duration)

	// Kill forcefully terminates the remote command
	Kill() error
}

An InstanceCmd represents a remote command to be run on an Instance This interface is similar to that of os.exec.Cmd

type InstanceCmdError

type InstanceCmdError struct {
	ReturnCode int
	Command    string
	Stderr     string
}

InstanceCmdError includes extra information when commands fail

func (*InstanceCmdError) Error

func (e *InstanceCmdError) Error() string

type Launcher

type Launcher interface {
	// Do any preparation necessary before starting. This is idempotent, and
	// does not need to be explicitly called by the client, as it will be
	// automatically called by Start as necessary.
	Prepare() error

	// Starts the instance, returning a Connector that can be used to communicate with it
	Start() (Connector, error)

	// Returns true iff the instance is running.
	IsRunning() (bool, error)

	// Stops the instance. This is allowed to take up to 3 seconds to return.
	Kill() error

	// Dump any available system or debug logs to `out`
	GetLogs(out io.Writer) error
}

A Launcher manages the lifecycle of an instance; e.g. starting and stopping

type QemuLauncher

type QemuLauncher struct {
	Pid    int
	TmpDir string
	// contains filtered or unexported fields
}

A QemuLauncher starts Fuchsia on QEMU

func NewQemuLauncher

func NewQemuLauncher(build Build) *QemuLauncher

NewQemuLauncher constructs a new QemuLauncher

func (*QemuLauncher) GetLogs

func (q *QemuLauncher) GetLogs(out io.Writer) error

GetLogs writes any system logs from QEMU to `out`

func (*QemuLauncher) IsRunning

func (q *QemuLauncher) IsRunning() (bool, error)

IsRunning checks if the qemu process is alive

func (*QemuLauncher) Kill

func (q *QemuLauncher) Kill() error

Kill tells the QEMU process to terminate, and cleans up the TmpDir

func (*QemuLauncher) Prepare

func (q *QemuLauncher) Prepare() (returnErr error)

Prepare files that are needed by QEMU, if they haven't already been prepared.

If Prepare succeeds, it is up to the caller to clean up by calling Kill later. However, if it fails, any resources will have been automatically released.

func (*QemuLauncher) Start

func (q *QemuLauncher) Start() (conn Connector, returnErr error)

Start launches QEMU and waits for it to get through the basic boot sequence. Note that networking will not necessarily be fully up by the time Start() returns

If Start succeeds, it is up to the caller to clean up by calling Kill later. However, if it fails, any resources will have been automatically released.

type SSHConnector

type SSHConnector struct {
	// Host can be any IP or hostname as accepted by net.Dial
	Host string
	Port int
	// Key is a path to the SSH private key that should be used for
	// authentication
	Key string
	// contains filtered or unexported fields
}

An SSHConnector is a Connector that uses SSH/SFTP for transport Note: exported fields will be serialized to the handle

func (*SSHConnector) Close

func (c *SSHConnector) Close()

Close any open connections

func (*SSHConnector) Command

func (c *SSHConnector) Command(name string, args ...string) InstanceCmd

Command returns an InstanceCmd that can be used to given command over SSH

func (*SSHConnector) Connect

func (c *SSHConnector) Connect() error

Connect to the remote server

func (*SSHConnector) Get

func (c *SSHConnector) Get(targetSrc string, hostDst string) error

Get fetches files over SFTP

func (*SSHConnector) GetSysLog

func (c *SSHConnector) GetSysLog(pid int) (string, error)

GetSysLog will fetch the syslog by running a remote command

func (*SSHConnector) Put

func (c *SSHConnector) Put(hostSrc string, targetDst string) error

Put uploads files over SFTP

type SSHInstanceCmd

type SSHInstanceCmd struct {
	// contains filtered or unexported fields
}

A SSHInstanceCmd represents a command to be run over SSH

func (*SSHInstanceCmd) Kill

func (c *SSHInstanceCmd) Kill() error

Kill sends a KILL signal to the remote process

func (*SSHInstanceCmd) Output

func (c *SSHInstanceCmd) Output() ([]byte, error)

Output executes the command and returns its output

func (*SSHInstanceCmd) Run

func (c *SSHInstanceCmd) Run() error

Run runs the command to completion

func (*SSHInstanceCmd) SetTimeout

func (c *SSHInstanceCmd) SetTimeout(duration time.Duration)

SetTimeout sets the global timeout

func (*SSHInstanceCmd) Start

func (c *SSHInstanceCmd) Start() error

Start the command, but don't wait for it to complete

func (*SSHInstanceCmd) StdinPipe

func (c *SSHInstanceCmd) StdinPipe() (io.WriteCloser, error)

StdinPipe returns a pipe connected to the command's input

func (*SSHInstanceCmd) StdoutPipe

func (c *SSHInstanceCmd) StdoutPipe() (io.ReadCloser, error)

StdoutPipe returns a pipe connected to the command's output TODO(fxbug.dev/45424): this currently includes stderr in addition to stdout TODO(fxbug.dev/45424): use ssh.Session's implementation of pipe stuff, etc

func (*SSHInstanceCmd) Wait

func (c *SSHInstanceCmd) Wait() error

Wait for the remote command to complete

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL