| // 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) -> (); |
| }; |