Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 11 additions & 26 deletions doc/dev_ref/fuzzing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
--------------------------
Expand Down
49 changes: 46 additions & 3 deletions src/fuzzer/fuzzers.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
#ifndef BOTAN_FUZZER_DRIVER_H_
#define BOTAN_FUZZER_DRIVER_H_

#include <botan/chacha_rng.h>
#include <botan/exceptn.h>
#include <botan/internal/target_info.h>

#include <memory>
#include <span>
#include <fstream>
#include <iostream>
#include <stdint.h>
Expand All @@ -20,6 +22,48 @@ static constexpr size_t max_fuzzer_input_size = 8192;

extern void fuzz(std::span<const uint8_t> 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<uint8_t> output, std::span<const uint8_t> /*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<uint8_t>(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);
Expand Down Expand Up @@ -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<Botan::RandomNumberGenerator> fuzzer_rng_as_shared() {
static const std::shared_ptr<Botan::ChaCha_RNG> rng =
std::make_shared<Botan::ChaCha_RNG>(Botan::secure_vector<uint8_t>(32));
static const std::shared_ptr<Deterministic_Fuzzer_RNG> rng = std::make_shared<Deterministic_Fuzzer_RNG>();
return rng;
}

Expand Down
Loading