Skip to content

Commit

Permalink
test: Add some support functions to make writing fuzzers easier.
Browse files Browse the repository at this point in the history
  • Loading branch information
iphydf committed Mar 27, 2022
1 parent ac3e8fe commit 94d6086
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 49 deletions.
5 changes: 5 additions & 0 deletions .github/scripts/cmake-osx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ add_ld_flag -undefined error
# Make compilation error on a warning
add_flag -Werror

# Allow _Static_assert. Supported C11 extensions are fine, since we have several
# C99-only compilers we test against anyway. Anything that passes all the
# compilers we use is fine.
add_c_flag -Wno-c11-extensions

cmake -B_build -H. \
-DCMAKE_C_FLAGS="$C_FLAGS" \
-DCMAKE_CXX_FLAGS="$CXX_FLAGS" \
Expand Down
7 changes: 7 additions & 0 deletions testing/fuzzing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ cc_library(
visibility = ["//c-toxcore:__subpackages__"],
)

cc_library(
name = "fuzz_support",
srcs = ["fuzz_support.cc"],
hdrs = ["fuzz_support.h"],
visibility = ["//c-toxcore:__subpackages__"],
)

cc_fuzz_test(
name = "bootstrap_fuzzer",
srcs = ["bootstrap_harness.cc"],
Expand Down
1 change: 1 addition & 0 deletions testing/fuzzing/fuzz_support.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "fuzz_support.h"
87 changes: 87 additions & 0 deletions testing/fuzzing/fuzz_support.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2021 The TokTok team.
*/

#ifndef C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
#define C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H

#include <cstdint>
#include <cstdlib>

struct Fuzz_Data {
const uint8_t *data;
std::size_t size;

uint8_t consume1() {
const uint8_t val = data[0];
++data;
--size;
return val;
}

const uint8_t *consume(std::size_t count) {
const uint8_t *val = data;
data += count;
size -= count;
return val;
}
};

/** @brief Consumes 1 byte of the fuzzer input or returns if no data available.
*
* This advances the fuzzer input data by 1 byte and consumes that byte in the
* declaration.
*
* @example
* @code
* CONSUME1_OR_RETURN(const uint8_t one_byte, input);
* @endcode
*/
#define CONSUME1_OR_RETURN(DECL, INPUT) \
if (INPUT.size < 1) { \
return; \
} \
DECL = INPUT.consume1()

/** @brief Consumes SIZE bytes of the fuzzer input or returns if not enough data available.
*
* This advances the fuzzer input data by SIZE byte and consumes those bytes in
* the declaration. If less than SIZE bytes are available in the fuzzer input,
* this macro returns from the enclosing function.
*
* @example
* @code
* CONSUME_OR_RETURN(const uint8_t *ten_bytes, input, 10);
* @endcode
*/
#define CONSUME_OR_RETURN(DECL, INPUT, SIZE) \
if (INPUT.size < SIZE) { \
return; \
} \
DECL = INPUT.consume(SIZE)

inline void fuzz_select_target(uint8_t selector, Fuzz_Data input)
{
// The selector selected no function, so we do nothing and rely on the
// fuzzer to come up with a better selector.
}

template<typename Arg, typename ...Args>
void fuzz_select_target(uint8_t selector, Fuzz_Data input, Arg fn, Args ...args)
{
if (selector == sizeof...(Args)) {
return fn(input);
}
return fuzz_select_target(selector - 1, input, args...);
}

template<typename ...Args>
void fuzz_select_target(const uint8_t *data, std::size_t size, Args ...args)
{
Fuzz_Data input{data, size};

CONSUME1_OR_RETURN(uint8_t selector, input);
return fuzz_select_target(selector, input, args...);
}

#endif // C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
5 changes: 4 additions & 1 deletion toxcore/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,10 @@ cc_fuzz_test(
name = "DHT_fuzz_test",
srcs = ["DHT_fuzz_test.cc"],
corpus = ["//tools/toktok-fuzzer/corpus:DHT_fuzz_test"],
deps = [":DHT"],
deps = [
":DHT",
"//c-toxcore/testing/fuzzing:fuzz_support",
],
)

cc_library(
Expand Down
65 changes: 17 additions & 48 deletions toxcore/DHT_fuzz_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,31 @@
#include <cstdlib>
#include <vector>

#include "../testing/fuzzing/fuzz_support.h"

namespace {

void TestHandleRequest(const uint8_t *input_data, size_t input_size)
void TestHandleRequest(Fuzz_Data input)
{
const uint8_t *data = input_data;
size_t size = input_size;

const uint8_t *self_public_key = data;
data += CRYPTO_PUBLIC_KEY_SIZE;
size -= CRYPTO_PUBLIC_KEY_SIZE;

const uint8_t *self_secret_key = data;
data += CRYPTO_SECRET_KEY_SIZE;
size -= CRYPTO_SECRET_KEY_SIZE;
CONSUME_OR_RETURN(const uint8_t *self_public_key, input, CRYPTO_PUBLIC_KEY_SIZE);
CONSUME_OR_RETURN(const uint8_t *self_secret_key, input, CRYPTO_SECRET_KEY_SIZE);

uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t request[MAX_CRYPTO_REQUEST_SIZE];
uint8_t request_id;
handle_request(self_public_key, self_secret_key, public_key, request, &request_id, data, size);
handle_request(
self_public_key, self_secret_key, public_key, request, &request_id, input.data, input.size);
}

void TestUnpackNodes(const uint8_t *input_data, size_t input_size)
void TestUnpackNodes(Fuzz_Data input)
{
const uint8_t *data = input_data;
size_t size = input_size;

if (size < 1) {
return;
}

const bool tcp_enabled = data[0];
++data;
--size;
CONSUME1_OR_RETURN(const bool tcp_enabled, input);

Node_format nodes[5];
const uint16_t node_count = 5;
Node_format nodes[node_count];
uint16_t processed_data_len;
const int packed_count = unpack_nodes(nodes, 5, &processed_data_len, data, size, tcp_enabled);
const int packed_count
= unpack_nodes(nodes, node_count, &processed_data_len, input.data, input.size, tcp_enabled);
if (packed_count > 0) {
Logger *logger = logger_new();
std::vector<uint8_t> packed(packed_count * PACKED_NODE_SIZE_IP6);
Expand All @@ -53,28 +41,9 @@ void TestUnpackNodes(const uint8_t *input_data, size_t input_size)

} // namespace

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *input_data, size_t input_size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *input_data, size_t input_size)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
const uint8_t *data = input_data;
size_t size = input_size;

if (size < 1) {
return 0;
}

const uint8_t func = data[0];
++data;
--size;

switch (func) {
case 0:
TestHandleRequest(data, size);
return 0;
case 1:
TestUnpackNodes(data, size);
return 0;
default:
return 0;
}
fuzz_select_target(data, size, TestHandleRequest, TestUnpackNodes);
return 0;
}

0 comments on commit 94d6086

Please sign in to comment.