blob: 121b7bd6942bd266a8a644e81706d8c0b450f4a3 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.fuzzer;
using zx;
/// Indicates the result of a long-running fuzzing workflow.
///
/// Fuzzers have several "long-running" workflows; that is, the fuzzer may
/// perform actions for an indefinite period of time. Fuzzing itself is the most
/// notable example, as the fuzzing engine may continuously generate new inputs
/// until an error is found. This workflow is represented by the `Fuzz` method
/// below. Other long-running workflows include `TryOne`, `Cleanse`, `Minimize`
/// and `Merge`.
///
/// These workflows continue executing after their associated call returns. Only
/// one workflow at a time may be executing. Callers can use `AddMonitor` to
/// monitor the status of the workflow, and `GetArtifact` to retrieve the
/// `Result` and optionally associated `Input` when it completes.
type Result = flexible enum : uint32 {
/// The associated input did not cause any errors to be detected when tried.
NO_ERRORS = 1;
/// Trying the associated input triggered a memory allocation by an
/// instrumented process that exceeded the configured limit. Some fuzzing
/// engines, such as libFuzzer, may not distinguish between this result and
/// `OOM`. To differentiate, examine the fuzzer output.
BAD_MALLOC = 2;
/// Trying the associated input triggered an exception in an instrumented
/// process.
CRASH = 3;
/// Trying the associated input triggered an error in an instrumented
/// process that was detected by a sanitizer runtime.
DEATH = 4;
/// Trying the associated input caused an instrumented process to exit
/// unexpectedly. Some fuzzing engines such as libFuzzer may combine this
/// result with `CRASH`. To differentiate, examine the fuzzer output.
EXIT = 5;
/// Trying the associated input triggered a memory leak in an instrumented
/// process.
LEAK = 6;
/// Trying the associated input caused an instrumented process's memory
/// usage to exceed the configured limit.
OOM = 7;
/// Trying the associated input took longer than the configured limit.
TIMEOUT = 8;
/// The associated input was produced by finding the shortest input that
/// produces the same error as an original input. See `Minimize`.
MINIMIZED = 9;
/// The associated input was produced by replacing bytes in an original
/// input with PII-free values while preserving the error produced. See
/// `Cleanse`.
CLEANSED = 10;
/// The fuzzer corpus has been compacted to only include the shortest inputs
/// that preserve overall coverage. This workflow does not have an
/// associated input. See `Merge`.
MERGED = 11;
};
/// Encapsulation of a fuzzer input transferred over a socket, e.g. between a
/// host and device via overnet.
type Input = resource struct {
/// Socket that can be used to read the data.
socket zx.Handle:SOCKET;
/// The total amount of data to be transferred.
size uint64;
};
/// Encapsulates the result of a long-running fuzzing workflow and optionally
/// the input that caused it, depending on the workflow.
//
// TODO(https://fxbug.dev/42074956): Include workflow enum.
type Artifact = resource table {
/// Result of executing the long-running workflow.
1: result Result;
/// Optional fuzzer input produced by a specific long-running workflow. This
/// may be:
///
/// * A discovered input in the case of `Fuzz`
/// * A constructed input in the cases of `Cleanse` and `Minimize`.
/// * Omitted in the cases of `TryOne` and `Merge`.
2: input Input;
/// An error generated during a long-running workflow. These errors are
/// distinct from those that result from validating workflow requests and
/// are documented for the workflow methods below. These errors result from
/// unexpected framework failure. For example, if libFuzzer fails due to an
/// internal error, the engine will report it via this field.
///
/// The `result` and `input` fields are invalid if this field is present and
/// anything other than `ZX_OK`.
3: error zx.Status;
};
/// Marker indicating the last message in a diagnostic output stream.
///
/// In addition to an `Artifact`, long-running workflows may also produce the
/// standard output, standard error, and system logs. These fuzzer output
/// streams are provided by `fuchsia.test_manager/RunBuilder` and have no
/// guaranteed order with respect to FIDL responses. As a result, the streams
/// need to include an "in-band" signal that indicates when they are complete
/// for a particular workflow. Clients processing the fuzzer output may use this
/// marker to synchronize the streams and the FIDL response for `GetArtifact`.
///
/// The string is intentionally somewhat long to mitigate the likelihood of it
/// being emitted by the code under test.
///
const DONE_MARKER string = "DONE: A long-running `fuchsia.fuzzer.Controller` workflow is complete.";
/// Provides the management interface for fuzzing.
///
/// This protocol is implemented by the fuzzing engine. Clients for this
/// protocol are provided by `fuchsia.fuzzer/ControllerProvider.Connect`.
///
/// The channel is closed when the fuzzer is no longer needed, and on error.
/// Clients should exit and not attempt to reconnect.
closed protocol Controller {
/// Sets various execution and error detection parameters. This may be
/// called multiple times; only the most recently received options are used.
/// If the `Options` parameter omits one or more fields, those parameters
/// are unchanged in the fuzzer. Until the initial call to this method, the
/// fuzzer should assume the default values for `Options`.
///
/// + request `options` the execution and error detection parameters.
/// * error one of the following:
/// * error
/// * `ZX_ERR_BAD_STATE` if a long-running call such as `Execute`,
/// `Cleanse`, `Minimize`, `Fuzz`, or `Merge` is in progress.
/// * `ZX_ERR_NOT_SUPPORTED` if a value provided for an option is not
/// supported by the engine. Check the logs for additional details.
strict Configure(struct {
options Options;
}) -> () error zx.Status;
/// Gets the current values for the various execution and error detection
/// parameters.
///
/// - response `options` the execution and error detection parameters.
strict GetOptions() -> (struct {
options Options;
});
/// Writes the provided `input` to either the "seed" or "live" `corpus`.
/// Returns an error if transferring the input fails; see `Input` for
/// details.
///
/// + request `corpus` the type of corpus to add to.
/// + request `input` the sequence of bytes to add as a test input.
/// * error one of the following:
/// * `ZX_ERR_INVALID_ARGS` if corpus type is invalid.
/// * A socket error if transferring the input fails.
strict AddToCorpus(resource struct {
corpus Corpus;
input Input;
}) -> () error zx.Status;
/// Connects a `corpus_reader` for either the "seed" or "live" corpus.
///
/// + request `corpus` the type of corpus to read from.
/// + request `corpus_reader` the client used to send test inputs.
strict ReadCorpus(resource struct {
corpus Corpus;
corpus_reader client_end:CorpusReader;
}) -> ();
/// Parses and loads an AFL-style dictionary. Invalid entries are logged and
/// skipped.
///
/// See also:
///
/// * https://github.com/mirrorer/afl/blob/master/dictionaries/README.dictionaries
///
/// + request `dictionary` the AFL-style dictionary
/// * error one of the following:
/// * A socket error if transferring the input fails.
/// *`ZX_ERR_INVALID_ARGS` if parsing the dictionary fails.
strict WriteDictionary(resource struct {
dictionary Input;
}) -> () error zx.Status;
/// Returns the current dictionary as an Input, which may be empty.
///
/// - response `dictionary` the current AFL-style dictionary.
strict ReadDictionary() -> (resource struct {
dictionary Input;
});
/// Installs a `Monitor` to push status. To pull status instead, use
/// `GetStatus`.
///
/// + request `monitor` the client used to send status updates.
strict AddMonitor(resource struct {
monitor client_end:Monitor;
}) -> ();
/// Runs the normal fuzzing feedback loop:
///
/// 1. Selects an input from the corpus.
/// 2. Mutates the input.
/// 3. Uses the `TargetAdapter` to execute the input.
/// 4. Checks feedback from the `InstrumentedProcesses`.
/// 5. If the input produced useful feedback, adds it to the corpus.
///
/// This call returns quickly, but the loop continues until one of three
/// conditions is met:
///
/// 1. The configured, non-zero number of `runs` has been reached.
/// 2. The configured, non-zero `duration` elapses.
/// 3. An error is detected, and returned.
///
/// See `Result` for more details on long running workflows such as this
/// one.
///
/// * error `ZX_ERR_BAD_STATE` if another long-running workflow is in
/// progress.
strict Fuzz() -> () error zx.Status;
/// Executes the target code with a single `test_input`.
///
/// See `Result` for more details on long running workflows such as this
/// one.
///
/// + request `input` the sequence of bytes to use with the fuzz target.
/// * error one of the following:
/// * `ZX_ERR_BAD_STATE` if another long-running workflow is in
/// progress.
/// * A socket error if transferring the input fails.
strict TryOne(resource struct {
test_input Input;
}) -> () error zx.Status;
/// Attempts to find the smallest input that produces the same error as the
/// given `test_input`,
/// constrained by the configured `total_time` and/or `runs` options.
///
/// See `Result` for more details on long running workflows such as this
/// one.
///
/// + request `input` the sequence of bytes to minimize.
/// * error one of the following:
/// * `ZX_ERR_BAD_STATE` if another long-running workflow is in
/// progress.
/// * A socket error if transferring the input fails.
/// * `ZX_ERR_INVALID_ARGS` if the provided `test_input` does not cause
/// an error.
strict Minimize(resource struct {
test_input Input;
}) -> () error zx.Status;
/// Attempts to replace bytes of the given `test_input` with "filler" bytes,
/// e.g. \x00, \xFF, without changing the error produced.
///
/// See `Result` for more details on long running workflows such as this
/// one.
///
/// To preserve backwards compatibility with libFuzzer and ClusterFuzz, an
/// input that produces no result is *not* considered an error, and is
/// returned as-is.
///
/// + request `input` the sequence of bytes to cleanse.
/// * error one of the following:
/// * `ZX_ERR_BAD_STATE` if another long-running workflow is in
/// progress.
/// * A socket error if transferring the input fails.
strict Cleanse(resource struct {
test_input Input;
}) -> () error zx.Status;
/// Attempts to shrink the corpora. Inputs from the seed corpus will be
/// preserved. All other inputs will be sorted by amount of feedback
/// produced and input size, and only those inputs that add new feedback not
/// seen earlier in the sequence will be kept.
///
/// See `Result` for more details on long running workflows such as this
/// one.
///
/// * error one of the following:
/// * `ZX_ERR_BAD_STATE` if another long-running workflow is in
/// progress.
/// * `ZX_ERR_INVALID_ARGS` if an input in the seed corpus causes an
/// error. Inputs in the live corpus that cause errors are skipped.
strict Merge() -> () error zx.Status;
/// Returns various fuzzing metrics, e.g. total coverage, speed, etc.
///
/// - response `status` the current value of fuzzing metrics.
strict GetStatus() -> (struct {
status Status;
});
/// Returns the results of a long-running workflow.
///
/// This method uses the
/// ["hanging get" pattern](https://fuchsia.dev/fuchsia-src/development/api/fidl#hanging-get).
/// Upon the first call for a given connection, it will immediately return
/// the controller's current artifact. Upon subsequent calls, it will block
/// until the controller's artifact changes before returning. Clients should
/// use `GetStatus` to ensure the fuzzer is not idle before making a
/// blocking call to `WatchArtifact`.
///
/// Combined with the `Status.running` value obtained from `GetStatus`, this
/// allows a (re-)connecting client to infer the state of the fuzzer:
///
/// * If the fuzzer is idle and has an empty artifact, then it is
/// unchanged since the last connection, if any.
/// * If the fuzzer is running and has an empty artifact, then it is
/// performing a long-running workflow started by a previous connection.
/// The client may call `WatchArtifact` again to wait for the workflow
/// to complete.
/// * If the fuzzer is idle and has a non-empty artifact, then it has
/// completed a long-running workflow since the last connection.
///
/// It is not an error for clients to disconnect while waiting for a
/// response from this method. This method is intended to allow clients to
/// resume waiting for a long-running workflow to complete after
/// intentionally or inadvertently being disconnected for an indefinite
/// amount of time.
///
/// - response `artifact` the most recent result and/or error-causing input.
strict WatchArtifact() -> (resource struct {
artifact Artifact;
});
};
/// Provides a `Controller` implementation.
///
/// This protocol is implemented by the fuzzing engine. This capability is *not*
/// routed. Instead, the engine uses the `fuchsia.fuzzer/Registry` channel
/// provided by the fuzz-test-runner to send the client end of this interface to
/// the fuzz-registry.
///
/// The fuzz-registry will close the channel upon error, or upon its own exit.
/// The fuzzer should exit and not attempt to reconnect when on channel close.
closed protocol ControllerProvider {
/// Connects a client to the fuzzer.
///
/// Within the component fuzzing framework, the fuzz-manager forwards
/// `Controller` connection requests to the fuzz-registry, which uses
/// clients of this interface provided by the fuzzers themselves to perform
/// the connection.
///
/// At most one client can be connected to a controller at any given time.
/// A subsequent call to `Connect` will preempt and replace the existing
/// connection.
///
/// + request `controller` the connection from the client.
strict Connect(resource struct {
controller server_end:Controller;
}) -> ();
/// Interrupt any current workflow, closes the channel, and exits the
/// fuzzing engine.
strict Stop();
};