diff --git a/doc/dev_ref/fuzzing.rst b/doc/dev_ref/fuzzing.rst index 21891450f62..501ad337f3f 100644 --- a/doc/dev_ref/fuzzing.rst +++ b/doc/dev_ref/fuzzing.rst @@ -9,16 +9,19 @@ the library. Fuzzing with libFuzzer ------------------------ -As of Clang Version 6.0 libFuzzer is automatically included in the compiler. Therefore you don't need to install any new software. +libFuzzer is provided by Clang's sanitizer runtime. You do not need a separate +libFuzzer checkout; link the fuzz targets with ``-fsanitize=fuzzer``. You can build the fuzzers by running :: $ ./configure.py --cc=clang --build-fuzzer=libfuzzer --enable-sanitizers=fuzzer $ make fuzzers -The option `--enable-sanitizers=fuzzer` compiles the library for coverage-guided fuzzing. -You can add additional sanitizers like `address`, `undefined` and `memory` or with/without -additional information during building by either adding `--unsafe-fuzzer-mode` or `--with-debug-info`. -The `coverage` sanitizer is not compatible with this configuration. +The option ``--enable-sanitizers=fuzzer`` adds the required compile and link +flags for coverage-guided fuzzing. You can add additional sanitizers like +``address``, ``undefined`` and ``memory`` or with/without additional +information during building by either adding ``--unsafe-fuzzer-mode`` or +``--with-debug-info``. The ``coverage`` sanitizer is not compatible with this +configuration. If you want to link additional libraries you can use the `--with-fuzzer-lib` option while configuring the build with configure.py. @@ -34,27 +37,9 @@ with you can test the Fuzzers. -Fuzzing with AFL++ --------------------- - -Please make sure that you have installed AFL++ according to https://aflplus.plus/building/. -The version of Clang should match the version of `afl-clang-fast++`/ `afl-clang-fast`. -You can fuzz with AFL++ in LLVM mode (https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.llvm.md) by running :: - - $ ./configure.py --cc=clang --with-sanitizers --build-fuzzer=afl --unsafe-fuzzer-mode --cc-bin=afl-clang-fast++ - $ make fuzzers - -For AFL++ in GCC mode make sure that you have `afl-g++-fast` installed. -Otherwise follow https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.gcc_plugin.md to build and install it. -You can configure the build by running :: - - $ ./configure.py --cc=gcc --with-sanitizers --build-fuzzer=afl --unsafe-fuzzer-mode --cc-bin=afl-g++-fast - $ make fuzzers - -The fuzzer binaries will be in `build/fuzzer`. To run them you need to -run under `afl-fuzz`:: - - $ afl-fuzz -i corpus_path -o output_path ./build/fuzzer/binary +Legacy AFL++ support remains available through ``--build-fuzzer=afl``, but it +is not actively tested. If you use it, configure Botan with a matching AFL++ +compiler wrapper and run the resulting binary under ``afl-fuzz``. Fuzzing with TLS-Attacker -------------------------- diff --git a/src/fuzzer/fuzzers.h b/src/fuzzer/fuzzers.h index 104c449cc4b..fe4b46adb07 100644 --- a/src/fuzzer/fuzzers.h +++ b/src/fuzzer/fuzzers.h @@ -7,9 +7,11 @@ #ifndef BOTAN_FUZZER_DRIVER_H_ #define BOTAN_FUZZER_DRIVER_H_ -#include #include #include + +#include +#include #include #include #include @@ -20,6 +22,48 @@ static constexpr size_t max_fuzzer_input_size = 8192; extern void fuzz(std::span in); +class Deterministic_Fuzzer_RNG final : public Botan::RandomNumberGenerator { + public: + bool accepts_input() const override { return false; } + + std::string name() const override { return "Deterministic_Fuzzer_RNG"; } + + void clear() override { + m_state = initial_state; + m_buffer = 0; + m_bytes_left = 0; + } + + bool is_seeded() const override { return true; } + + private: + void fill_bytes_with_input(std::span output, std::span /*ignored*/) override { + for(auto& out_byte : output) { + if(m_bytes_left == 0) { + m_buffer = next_word(); + m_bytes_left = sizeof(m_buffer); + } + + out_byte = static_cast(m_buffer & 0xFF); + m_buffer >>= 8; + --m_bytes_left; + } + } + + uint64_t next_word() { + m_state ^= m_state >> 12; + m_state ^= m_state << 25; + m_state ^= m_state >> 27; + return m_state * 0x2545F4914F6CDD1DULL; + } + + static constexpr uint64_t initial_state = 0x9E3779B97F4A7C15ULL; + + uint64_t m_state = initial_state; + uint64_t m_buffer = 0; + size_t m_bytes_left = 0; +}; + // Need to declare these before defining them; extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv); extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len); @@ -54,8 +98,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len) { // Some helpers for the fuzzer jigs inline std::shared_ptr fuzzer_rng_as_shared() { - static const std::shared_ptr rng = - std::make_shared(Botan::secure_vector(32)); + static const std::shared_ptr rng = std::make_shared(); return rng; }