blob: 7b33b5e6c034adb82fa46652a759318e764bf430 [file] [log] [blame]
// Copyright 2020 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.
/// A library of cross-process fuzzing protocols.
///
/// A fuzzer can be described in three parts:
/// 1. The code under test.
/// 2. A fuzz target function that maps each test input to the interface of the code under test.
/// 3. A fuzzing engine that generates new test inputs.
/// For more details, see https://fuchsia.dev/fuchsia-src/development/testing/fuzzing/overview
///
/// LLVM's libFuzzer is a coverage-guided fuzzing engine. It includes a pair of interfaces for
/// coordinating test execution and coverage collection from one or more remote processes. LibFuzzer
/// refers to the methods invoked by the engine process and executed in a remote process as the
/// "FuzzerRemote" interface, and to the methods invoked by remote processes and executed in the
/// engine processto the "FuzzerProxy" interface.
///
/// Notably, these interfaces do NOT specify how calls are forwarded from the one process to the
/// other. Instead, the libFuzzer runtime (in the engine process) and the libFuzzerRemote runtime
/// (in the remote processes) both assume they will be linked against a transport library that
/// implements the each interface in the other process, i.e.:
/// * The engine process is linked against an implementation of the FuzzerRemote interface that
/// forwards to the remote process.
/// * The remote process is linked against an implementation of the FuzzerProxy interface that
/// forwards to the engine process.
///
/// The protocols in this library are designed to match these interfaces expectations and provide
/// a compatible Fuchsia transport library for libFuzzer using FIDL and Zircon objects.
///
/// See also:
/// https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/fuzzer/FuzzerRemoteInterface.h
library fuchsia.fuzzer;
using fuchsia.mem;
using zx;
/// libFuzzer's FuzzerProxiedOptions are sent from the FuzzerProxy to the FuzzerRemote as an opaque
/// sequence of bytes.
///
/// See also:
/// https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/fuzzer/FuzzerRemoteInterface.h
const int32 MAX_OPTIONS_SIZE = 64;
alias FuzzerProxiedOptions = bytes:MAX_OPTIONS_SIZE;
// These errors correspond to the subset of libFuzzer's error callback that are expected to be
// detected in a remote process.
enum FuzzerError : uint8 {
CRASH = 1;
DEATH = 2;
EXIT = 3;
LEAK = 4;
MALLOC_LIMIT = 5;
RSS_LIMIT = 6;
};
/// Underlying transport for libFuzzer's FuzzerProxy interface on Fuchsia.
///
/// This protocol provides methods that remote processes can use to register themselves, their
/// coverage data, and any encountered errors with the fuzzing engine process. These methods should
/// only be used during set-up (Connect, AddCoverage) or tear-down (HandleError). All other
/// coordination between processes during fuzzing should use the objects shared during set-up, e.g.
/// the eventpair and VMOs.
[Discoverable]
protocol Proxy {
/// Registers the remote process with the fuzzing engine.
///
/// This method is called once per connection by the remote process to register its process ID,
/// as used by the libFuzzer interfaces, and an eventpair by which the engine and remote
/// processes can signal each other. The engine returns the subset of the fuzzing options that
/// are needed by the remote process.
///
/// The channel is closed on error. Clients should not attempt to reconnect.
Connect(uint64 pid, zx.handle:EVENTPAIR paired) -> (FuzzerProxiedOptions options);
/// Registers the provided VMOs to be used for inline 8-bit edge counters and PC tables.
///
/// This should be called for each element in a process's DSO map, i.e. for the process itself
/// and any shared objects it loads. The fuzzing engine will exit if it encounters any errors in
/// setting up the shared coverage.
///
/// The channel is closed on error. Clients should not attempt to reconnect.
///
/// See also:
/// https://clang.llvm.org/docs/SanitizerCoverage.html#inline-8bit-counters
/// https://clang.llvm.org/docs/SanitizerCoverage.html#pc-table
AddCoverage(fuchsia.mem.Buffer inline_8bit_counters, fuchsia.mem.Buffer pcs) -> ();
/// Reports detection of a monitored error condition.
///
/// libFuzzer has a number of error conditions it monitors. It will halt fuzzing and report
/// detailed error information when these conditions are detected. With this method, the remote
/// process can notify the engine process of one of these errors. It also includes a generic
/// parameter used by some of the libFuzzer error callbacks (e.g. FuzzerMallocLimitCallback),
/// and a tear-off protocol for requesting further diagnostic information from the remote
/// process.
///
/// The channel is closed on error. Clients should not attempt to reconnect.
///
/// See also:
/// https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/fuzzer/FuzzerMonitor.h
HandleError(FuzzerError error, uint64 param, RemoteDiagnostics diagnostics);
};
/// Tear-off protocol for requesting diagnostics from a remote process.
///
/// When handling errors, libFuzzer will request that the remote process print certain types of
/// information as part of dumping detailed information related to the error. This protocol provides
/// the engine process a means to send these requests back to the remote process.
///
/// Implementations should take care to track the thread and/or other execution context that
/// instantiates the service, as requests should be satisfied from the same context.
protocol RemoteDiagnostics {
/// Prints the call stack from the thread that invoked Proxy.HandleError to the remote process's
/// standard output, which is either the engine process's stdout or logfile.
PrintStackTrace() -> ();
/// Prints the memory statistics from the thread that invoked Proxy.HandleError to the remote
/// process's standard output, which is either the engine process's stdout or logfile.
PrintMemoryProfile() -> ();
};
// Maximum data consumer label length.
const int32 MAX_LABEL_SIZE = 128;
/// Splits the engine process's fuzzer test input between multiple remote processes.
///
/// For traditional single-process fuzzers, the fuzzing engine generates a sequence of bytes known
/// as a test input that the fuzz target function uses to exercise the interface to the code under
/// test. For multi-process FIDL fuzzing, it may also need to provide data to fake dependencies of
/// the code under test, or "fakes", in addition to the fuzz target function.
///
/// When possible, these fakes should be implemented within the engine process itself and draw
/// directly from the provided test input. If the fakes must be executed in a separate process, they
/// can consume a portion of the test input using this protocol.
///
/// Implementations should split the single test input between the different consumers in a way that
/// is "fuzzer-stable", i.e. most mutations such as adding or removing bytes shouldn't radically
/// alter what data the consumers receive.
[Discoverable]
protocol DataProvider {
/// Associates a shared VMO with a partition label.
///
/// Registers the provided VMO to be used for transferring the test input of an additional data
/// consumer. The DataProvider implementation must provide a way to add labels before consumers
/// connect, and fuzzer authors must add them during initialization. This is required for the
/// DataProvider to be able to partition the test input in the same manner regardless of when
/// a data consumer connects. The provided eventpair should be used to signal when test input
/// data is available.
///
/// The channel is closed on error. Clients should not attempt to reconnect.
Register(string:MAX_LABEL_SIZE label, zx.handle:EVENTPAIR ep, fuchsia.mem.Buffer buf) -> ();
};