| // 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 client that maps each test input to the interface of the code under test. |
| /// 3. A fuzzing engine that generates new test inputs. |
| /// |
| /// Each execution of the code under test with a test input is a single fuzzing iteration. A fuzzer |
| /// will perform iterations repeatedly until a defect is found or some other stopping condition is |
| /// reached (e.g. a time limit). |
| /// |
| /// In coverage-guided fuzzing, the code under test is instrumented to provide code coverage |
| /// information back to the fuzzing engine. The engine maintains a set of coverage-increasing inputs |
| /// called a corpus, and mutates these inputs to create new ones. |
| /// |
| /// Source-based instrumentation can be added by the compiler, but this generally assumes all three |
| /// parts are combined into a single process. For general-purpose FIDL fuzzing on Fuchsia, these |
| /// parts need to be able to reside in different processes. The protocols in this library allow |
| /// the interactions between those parts to happen over FIDL interfaces. |
| /// |
| /// For more details, see https://fuchsia.dev/fuchsia-src/development/testing/fuzzing/overview |
| library fuchsia.fuzzer; |
| |
| using fuchsia.mem; |
| using zx; |
| |
| // Maximum data consumer label length. |
| const int32 MAX_LABEL_SIZE = 128; |
| |
| /// A list of libFuzzer options, as defined in https://llvm.org/docs/LibFuzzer.html#options. |
| alias EngineOptions = vector<string:MAX_OPTION_SIZE>:MAX_OPTION_COUNT; |
| const int32 MAX_OPTION_SIZE = 128; |
| const int32 MAX_OPTION_COUNT = 128; |
| |
| /// Fuzzing engine interface to FIDL framework |
| /// |
| /// When started, the fuzzing engine provides the |Coverage| and |DataProvider| interfaces, and |
| /// invokes the |LlvmFuzzer| interface to set up and begin fuzzing. This interface allows the |
| /// framework to provide the overall fuzzer configuration and wait for the engine to exit. |
| [Discoverable] |
| protocol Engine { |
| /// Starts the fuzzing engine. |
| /// |
| /// This method takes the data consumer labels and libFuzzer options described in |Arguments| |
| /// above. It performs fuzzing iterations repeatedly in a loop, and does not return until: |
| /// * The engine reaches a stopping condition, e.g. `-max_total_time=3600`. |
| /// * The engine detects an error, e.g. libFuzzer's crash handler is invoked. |
| /// |
| /// This method can only be called once. Additional calls will return an error. |
| Start(EngineOptions options) -> (zx.status result); |
| }; |
| |
| /// Aggregated sanitizer coverage data proxied from other processes. |
| /// |
| /// For cross-process fuzzing. the code under test needs to proxy its code coverage data back to |
| /// fuzzing engine. The Coverage protocol describes this action, with the code under test as the |
| /// client and the fuzzing engine as the server. There are two types of methods: |
| /// 1. Some coverage, such as inline 8-bit counters and PC tables, is written to specific memory |
| /// locations. This data is forwarded to engine by setting up shared buffers. These methods |
| /// correspond to the LLVM compiler_rt `__sanitizer_cov_*_init` functions supported by |
| /// libFuzzer. |
| /// 2. Other coverage is associated with specific machine instructions being called, e.g. CMP |
| /// instructions. Rather than provide each traced instruction to the engine in a separate FIDL |
| /// call, a shared buffer is set up and the instructions are batched. The traced instructions |
| /// correspond to the LLVM compiler_rt `__sanitizer_cov_trace_*` functions. |
| [Discoverable] |
| protocol Coverage { |
| /// Registers the provided VMO to be used for inline 8-bit edge counters. |
| /// |
| /// 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. On error, the fuzzing engine will close the channel with an |
| /// epitaph. |
| /// |
| /// See https://clang.llvm.org/docs/SanitizerCoverage.html#inline-8bit-counters |
| AddInline8BitCounters(fuchsia.mem.Buffer inline_8bit_counters) -> (); |
| |
| /// Registers the provided VMO to be used for a table of instrumented PCs. |
| /// |
| /// 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. On error, the fuzzing engine will close the channel with an |
| /// epitaph. |
| /// |
| /// See https://clang.llvm.org/docs/SanitizerCoverage.html#pc-table |
| AddPcTable(fuchsia.mem.Buffer pcs) -> (); |
| |
| /// Registers the provided VMO to be used as a circular buffer of traced instructions. |
| /// |
| /// This should be called once per client. Subsequent calls will replace the previous VMO. |
| /// On error, the fuzzing engine will close the channel with an epitaph. |
| /// |
| /// See https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow |
| AddTraces(zx.handle:VMO instruction_traces) -> (); |
| }; |
| |
| /// Partitions fuzzer test inputs for multiple consumers based on in-place labels. |
| /// |
| /// 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 need to provide data to fake dependencies of the |
| /// code under test in addition to the fuzz target function. To achieve this, the fuzzing engine can |
| /// acts as a server for this protocol with the fuzz target function and one or more of the proxies |
| /// as clients. |
| /// |
| /// 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 labels are typically provided as command-line arguments to the engine. |
| /// |
| /// Returns ZX_ERR_INVALID_ARGS if the engine does not recognize the label. |
| AddConsumer(string:MAX_LABEL_SIZE label, zx.handle:VMO vmo) -> (zx.status result); |
| }; |
| |
| /// FIDL interface for the libFuzzer interface function. |
| /// |
| /// This protocol is the analogue of the LLVMFuzzer* C ABI defined by |
| /// https://github.com/llvm/llvm-project/blob/HEAD/compiler-rt/lib/fuzzer/FuzzerInterface.h. |
| /// Currently, only the method corresponding to the mandatory fuzz target function is defined, i.e. |
| /// `extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);` |
| /// |
| /// The fuzzing engine is the client of this protocol. |
| [Discoverable] |
| protocol LlvmFuzzer { |
| /// FIDL equivalent of the startup initializtion function. |
| /// |
| /// The provided VMO will be used by the |DataProvider| to provide test input data for each |
| /// fuzzing iteration. |
| /// |
| /// The libFuzzer options, as described by https://llvm.org/docs/LibFuzzer.html#options are also |
| /// provided so that the client may modify and return them as described in |
| /// https://llvm.org/docs/LibFuzzer.html#startup-initialization. |
| /// |
| /// It is an error to call this method more than once. The channel is closed on error. |
| /// |
| /// This method should always return 0. The C ABI has reserved non-zero return values for future |
| /// use. |
| Initialize(zx.handle:VMO vmo, EngineOptions options) -> (int32 result, EngineOptions options); |
| |
| /// FIDL equivalent of the fuzz target function. |
| /// |
| /// See https://llvm.org/docs/LibFuzzer.html#fuzz-target for the C ABI equivalent. This method |
| /// should use the data provided by the |DataProvider| protocol above to invoke one or more FIDL |
| /// methods for the service under test. |
| /// |
| /// As with C ABI function, the fuzzing engine will invoke this protocol and method many |
| /// times with each invocation corresponding to a different fuzzing iteration. For each |
| /// iteration inputs, the engine's |DataProvider| will generate a test input by examining the |
| /// coverage data returned by the proxy associated with the code under test. |
| /// |
| /// This method should always return 0, even if the code under test encounters a recoverable |
| /// error. The C ABI has reserved non-zero return values for future use. |
| TestOneInput() -> (int32 result); |
| }; |