From 478ef39b39c212bf77921981e59ee38c1c2fcbd6 Mon Sep 17 00:00:00 2001 From: iphydf Date: Sun, 27 Mar 2022 17:17:53 +0000 Subject: [PATCH] test: Add some support functions to make writing fuzzers easier. --- testing/fuzzing/BUILD.bazel | 7 +++ testing/fuzzing/fuzz_support.cc | 1 + testing/fuzzing/fuzz_support.h | 87 +++++++++++++++++++++++++++++++++ toxcore/BUILD.bazel | 5 +- toxcore/DHT_fuzz_test.cc | 65 +++++++----------------- 5 files changed, 116 insertions(+), 49 deletions(-) create mode 100644 testing/fuzzing/fuzz_support.cc create mode 100644 testing/fuzzing/fuzz_support.h diff --git a/testing/fuzzing/BUILD.bazel b/testing/fuzzing/BUILD.bazel index 3b256dc7..eed1c6e5 100644 --- a/testing/fuzzing/BUILD.bazel +++ b/testing/fuzzing/BUILD.bazel @@ -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"], diff --git a/testing/fuzzing/fuzz_support.cc b/testing/fuzzing/fuzz_support.cc new file mode 100644 index 00000000..b9c4ec9a --- /dev/null +++ b/testing/fuzzing/fuzz_support.cc @@ -0,0 +1 @@ +#include "fuzz_support.h" diff --git a/testing/fuzzing/fuzz_support.h b/testing/fuzzing/fuzz_support.h new file mode 100644 index 00000000..ff358e7c --- /dev/null +++ b/testing/fuzzing/fuzz_support.h @@ -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 +#include + +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 +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 +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 diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel index f8868529..952d02cf 100644 --- a/toxcore/BUILD.bazel +++ b/toxcore/BUILD.bazel @@ -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( diff --git a/toxcore/DHT_fuzz_test.cc b/toxcore/DHT_fuzz_test.cc index a8fa7b34..65ddc169 100644 --- a/toxcore/DHT_fuzz_test.cc +++ b/toxcore/DHT_fuzz_test.cc @@ -3,43 +3,31 @@ #include #include +#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; + CONSUME1_OR_RETURN(const bool tcp_enabled, input); - if (size < 1) { - return; - } - - const bool tcp_enabled = data[0]; - ++data; - --size; - - 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 packed(packed_count * PACKED_NODE_SIZE_IP6); @@ -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; }