mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
test: Add fuzzer support functions for internal toxcore objects.
These help creating fuzzer fixtures with non-trivially constructed objects and takes care of cleaning them up afterwards so the fuzzer code can focus on the system under test.
This commit is contained in:
parent
c71b1218f8
commit
dec1399776
|
@ -15,6 +15,13 @@ cc_library(
|
||||||
visibility = ["//c-toxcore:__subpackages__"],
|
visibility = ["//c-toxcore:__subpackages__"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "fuzz_tox",
|
||||||
|
hdrs = ["fuzz_tox.h"],
|
||||||
|
visibility = ["//c-toxcore:__subpackages__"],
|
||||||
|
deps = [":fuzz_support"],
|
||||||
|
)
|
||||||
|
|
||||||
cc_fuzz_test(
|
cc_fuzz_test(
|
||||||
name = "bootstrap_fuzz_test",
|
name = "bootstrap_fuzz_test",
|
||||||
srcs = ["bootstrap_harness.cc"],
|
srcs = ["bootstrap_harness.cc"],
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* Copyright © 2021-2022 The TokTok team.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "fuzz_support.h"
|
#include "fuzz_support.h"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
* Copyright © 2021 The TokTok team.
|
* Copyright © 2021-2022 The TokTok team.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
|
#ifndef C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
|
||||||
|
@ -7,19 +7,29 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
struct Fuzz_Data {
|
struct Fuzz_Data {
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
|
|
||||||
uint8_t consume1() {
|
Fuzz_Data(const uint8_t *input_data, std::size_t input_size)
|
||||||
|
: data(input_data), size(input_size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Fuzz_Data &operator=(const Fuzz_Data &rhs) = delete;
|
||||||
|
Fuzz_Data(const Fuzz_Data &rhs) = delete;
|
||||||
|
|
||||||
|
uint8_t consume1()
|
||||||
|
{
|
||||||
const uint8_t val = data[0];
|
const uint8_t val = data[0];
|
||||||
++data;
|
++data;
|
||||||
--size;
|
--size;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *consume(std::size_t count) {
|
const uint8_t *consume(std::size_t count)
|
||||||
|
{
|
||||||
const uint8_t *val = data;
|
const uint8_t *val = data;
|
||||||
data += count;
|
data += count;
|
||||||
size -= count;
|
size -= count;
|
||||||
|
@ -38,9 +48,9 @@ struct Fuzz_Data {
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
#define CONSUME1_OR_RETURN(DECL, INPUT) \
|
#define CONSUME1_OR_RETURN(DECL, INPUT) \
|
||||||
if (INPUT.size < 1) { \
|
if (INPUT.size < 1) { \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
DECL = INPUT.consume1()
|
DECL = INPUT.consume1()
|
||||||
|
|
||||||
/** @brief Consumes SIZE bytes of the fuzzer input or returns if not enough data available.
|
/** @brief Consumes SIZE bytes of the fuzzer input or returns if not enough data available.
|
||||||
|
@ -55,33 +65,33 @@ struct Fuzz_Data {
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
#define CONSUME_OR_RETURN(DECL, INPUT, SIZE) \
|
#define CONSUME_OR_RETURN(DECL, INPUT, SIZE) \
|
||||||
if (INPUT.size < SIZE) { \
|
if (INPUT.size < SIZE) { \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
DECL = INPUT.consume(SIZE)
|
DECL = INPUT.consume(SIZE)
|
||||||
|
|
||||||
inline void fuzz_select_target(uint8_t selector, Fuzz_Data input)
|
inline void fuzz_select_target(uint8_t selector, Fuzz_Data &input)
|
||||||
{
|
{
|
||||||
// The selector selected no function, so we do nothing and rely on the
|
// The selector selected no function, so we do nothing and rely on the
|
||||||
// fuzzer to come up with a better selector.
|
// fuzzer to come up with a better selector.
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Arg, typename ...Args>
|
template <typename Arg, typename... Args>
|
||||||
void fuzz_select_target(uint8_t selector, Fuzz_Data input, Arg fn, Args ...args)
|
void fuzz_select_target(uint8_t selector, Fuzz_Data &input, Arg &&fn, Args &&... args)
|
||||||
{
|
{
|
||||||
if (selector == sizeof...(Args)) {
|
if (selector == sizeof...(Args)) {
|
||||||
return fn(input);
|
return fn(input);
|
||||||
}
|
}
|
||||||
return fuzz_select_target(selector - 1, input, args...);
|
return fuzz_select_target(selector - 1, input, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...Args>
|
template <typename... Args>
|
||||||
void fuzz_select_target(const uint8_t *data, std::size_t size, Args ...args)
|
void fuzz_select_target(const uint8_t *data, std::size_t size, Args &&... args)
|
||||||
{
|
{
|
||||||
Fuzz_Data input{data, size};
|
Fuzz_Data input{data, size};
|
||||||
|
|
||||||
CONSUME1_OR_RETURN(uint8_t selector, input);
|
CONSUME1_OR_RETURN(uint8_t selector, input);
|
||||||
return fuzz_select_target(selector, input, args...);
|
return fuzz_select_target(selector, input, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
|
#endif // C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
|
||||||
|
|
95
testing/fuzzing/fuzz_tox.h
Normal file
95
testing/fuzzing/fuzz_tox.h
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* Copyright © 2022 The TokTok team.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef C_TOXCORE_TESTING_FUZZING_FUZZ_TOX_H
|
||||||
|
#define C_TOXCORE_TESTING_FUZZING_FUZZ_TOX_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "../../toxcore/DHT.h"
|
||||||
|
#include "../../toxcore/logger.h"
|
||||||
|
#include "../../toxcore/network.h"
|
||||||
|
#include "fuzz_support.h"
|
||||||
|
|
||||||
|
constexpr uint16_t SIZE_IP_PORT = SIZE_IP6 + sizeof(uint16_t);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using Ptr = std::unique_ptr<T, void (*)(T *)>;
|
||||||
|
|
||||||
|
/** @brief Construct any Tox resource using fuzzer input data.
|
||||||
|
*
|
||||||
|
* Constructs (or fails by returning) a valid object of type T and passes it to
|
||||||
|
* a function specified on the rhs of `>>`. Takes care of cleaning up the
|
||||||
|
* resource after the specified function returns.
|
||||||
|
*
|
||||||
|
* Some `with` instances require additional inputs such as the `Fuzz_Data`
|
||||||
|
* reference or a logger.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
struct with;
|
||||||
|
|
||||||
|
/** @brief Construct a Logger without logging callback.
|
||||||
|
*/
|
||||||
|
template <>
|
||||||
|
struct with<Logger> {
|
||||||
|
template <typename F>
|
||||||
|
void operator>>(F &&f)
|
||||||
|
{
|
||||||
|
Ptr<Logger> logger(logger_new(), logger_kill);
|
||||||
|
assert(logger != nullptr);
|
||||||
|
f(std::move(logger));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Construct an IP_Port by unpacking fuzzer input with `unpack_ip_port`.
|
||||||
|
*/
|
||||||
|
template <>
|
||||||
|
struct with<IP_Port> {
|
||||||
|
Fuzz_Data &input_;
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void operator>>(F &&f)
|
||||||
|
{
|
||||||
|
CONSUME_OR_RETURN(const uint8_t *ipp_packed, input_, SIZE_IP_PORT);
|
||||||
|
IP_Port ipp;
|
||||||
|
unpack_ip_port(&ipp, ipp_packed, SIZE_IP6, true);
|
||||||
|
|
||||||
|
f(ipp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Construct a Networking_Core object using the Network vtable passed.
|
||||||
|
*
|
||||||
|
* Use `with<Logger>{} >> with<Networking_Core>{input, ns} >> ...` to construct
|
||||||
|
* a logger and pass it to the Networking_Core constructor function.
|
||||||
|
*/
|
||||||
|
template <>
|
||||||
|
struct with<Networking_Core> {
|
||||||
|
Fuzz_Data &input_;
|
||||||
|
const Network *ns_;
|
||||||
|
Ptr<Logger> logger_{nullptr, logger_kill};
|
||||||
|
|
||||||
|
friend with operator>>(with<Logger> f, with self)
|
||||||
|
{
|
||||||
|
f >> [&self](Ptr<Logger> logger) { self.logger_ = std::move(logger); };
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void operator>>(F &&f)
|
||||||
|
{
|
||||||
|
with<IP_Port>{input_} >> [&f, this](const IP_Port &ipp) {
|
||||||
|
Ptr<Networking_Core> net(
|
||||||
|
new_networking_ex(logger_.get(), ns_, &ipp.ip, ipp.port, ipp.port + 100, nullptr),
|
||||||
|
kill_networking);
|
||||||
|
if (net == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f(std::move(net));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // C_TOXCORE_TESTING_FUZZING_FUZZ_TOX_H
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void TestHandleRequest(Fuzz_Data input)
|
void TestHandleRequest(Fuzz_Data &input)
|
||||||
{
|
{
|
||||||
CONSUME_OR_RETURN(const uint8_t *self_public_key, input, CRYPTO_PUBLIC_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);
|
CONSUME_OR_RETURN(const uint8_t *self_secret_key, input, CRYPTO_SECRET_KEY_SIZE);
|
||||||
|
@ -19,7 +19,7 @@ void TestHandleRequest(Fuzz_Data input)
|
||||||
self_public_key, self_secret_key, public_key, request, &request_id, input.data, input.size);
|
self_public_key, self_secret_key, public_key, request, &request_id, input.data, input.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestUnpackNodes(Fuzz_Data input)
|
void TestUnpackNodes(Fuzz_Data &input)
|
||||||
{
|
{
|
||||||
CONSUME1_OR_RETURN(const bool tcp_enabled, input);
|
CONSUME1_OR_RETURN(const bool tcp_enabled, input);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void TestModListUnpack(Fuzz_Data input)
|
void TestModListUnpack(Fuzz_Data &input)
|
||||||
{
|
{
|
||||||
CONSUME1_OR_RETURN(const uint16_t num_mods, input);
|
CONSUME1_OR_RETURN(const uint16_t num_mods, input);
|
||||||
Moderation mods{};
|
Moderation mods{};
|
||||||
|
@ -12,7 +12,7 @@ void TestModListUnpack(Fuzz_Data input)
|
||||||
mod_list_cleanup(&mods);
|
mod_list_cleanup(&mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestSanctionsListUnpack(Fuzz_Data input)
|
void TestSanctionsListUnpack(Fuzz_Data &input)
|
||||||
{
|
{
|
||||||
Mod_Sanction sanctions[10];
|
Mod_Sanction sanctions[10];
|
||||||
Mod_Sanction_Creds creds;
|
Mod_Sanction_Creds creds;
|
||||||
|
@ -20,7 +20,7 @@ void TestSanctionsListUnpack(Fuzz_Data input)
|
||||||
sanctions_list_unpack(sanctions, &creds, 10, input.data, input.size, &processed_data_len);
|
sanctions_list_unpack(sanctions, &creds, 10, input.data, input.size, &processed_data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestSanctionCredsUnpack(Fuzz_Data input)
|
void TestSanctionCredsUnpack(Fuzz_Data &input)
|
||||||
{
|
{
|
||||||
CONSUME_OR_RETURN(const uint8_t *data, input, MOD_SANCTIONS_CREDS_SIZE);
|
CONSUME_OR_RETURN(const uint8_t *data, input, MOD_SANCTIONS_CREDS_SIZE);
|
||||||
Mod_Sanction_Creds creds;
|
Mod_Sanction_Creds creds;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user