diff --git a/testing/fuzzing/fuzz_support.cc b/testing/fuzzing/fuzz_support.cc index a96ccd5b..d44d7c9a 100644 --- a/testing/fuzzing/fuzz_support.cc +++ b/testing/fuzzing/fuzz_support.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -117,8 +118,7 @@ static constexpr Random_Funcs fuzz_random_funcs = { }; Fuzz_System::Fuzz_System(Fuzz_Data &input) - : clock(0) - , data(input) + : data(input) , sys(std::make_unique()) , ns(std::make_unique(Network{&fuzz_network_funcs, this})) , rng(std::make_unique(Random{&fuzz_random_funcs, this})) @@ -130,3 +130,75 @@ Fuzz_System::Fuzz_System(Fuzz_Data &input) } Fuzz_System::~Fuzz_System() { } + +static constexpr Network_Funcs null_network_funcs = { + /* .close = */ [](void *obj, int sock) { return 0; }, + /* .accept = */ [](void *obj, int sock) { return 2; }, + /* .bind = */ [](void *obj, int sock, const Network_Addr *addr) { return 0; }, + /* .listen = */ [](void *obj, int sock, int backlog) { return 0; }, + /* .recvbuf = */ ![](Null_System *self, int sock) { return 0; }, + /* .recv = */ + ![](Null_System *self, int sock, uint8_t *buf, size_t len) { + errno = ENOMEM; + return -1; + }, + /* .recvfrom = */ + ![](Null_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) { + errno = ENOMEM; + return -1; + }, + /* .send = */ + [](void *obj, int sock, const uint8_t *buf, size_t len) { + // Always succeed. + return static_cast(len); + }, + /* .sendto = */ + [](void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) { + // Always succeed. + return static_cast(len); + }, + /* .socket = */ [](void *obj, int domain, int type, int proto) { return 1; }, + /* .socket_nonblock = */ [](void *obj, int sock, bool nonblock) { return 0; }, + /* .getsockopt = */ + [](void *obj, int sock, int level, int optname, void *optval, size_t *optlen) { + memset(optval, 0, *optlen); + return 0; + }, + /* .setsockopt = */ + [](void *obj, int sock, int level, int optname, const void *optval, size_t optlen) { + return 0; + }, +}; + +static uint64_t simple_rng(uint64_t &seed) +{ + // https://nuclear.llnl.gov/CNP/rng/rngman/node4.html + seed = 2862933555777941757LL * seed + 3037000493LL; + return seed; +} + +static constexpr Random_Funcs null_random_funcs = { + /* .random_bytes = */ + ![](Null_System *self, uint8_t *bytes, size_t length) { + for (size_t i = 0; i < length; ++i) { + bytes[i] = simple_rng(self->seed) & 0xff; + } + }, + /* .random_uniform = */ + ![](Null_System *self, uint32_t upper_bound) { + return static_cast(simple_rng(self->seed)) % upper_bound; + }, +}; + +Null_System::Null_System() + : sys(std::make_unique()) + , ns(std::make_unique(Network{&null_network_funcs, this})) + , rng(std::make_unique(Random{&null_random_funcs, this})) +{ + sys->mono_time_callback = ![](Fuzz_System *self) { return self->clock; }; + sys->mono_time_user_data = this; + sys->ns = ns.get(); + sys->rng = rng.get(); +} + +Null_System::~Null_System() { } diff --git a/testing/fuzzing/fuzz_support.h b/testing/fuzzing/fuzz_support.h index b25a8076..9f274d89 100644 --- a/testing/fuzzing/fuzz_support.h +++ b/testing/fuzzing/fuzz_support.h @@ -100,15 +100,36 @@ void fuzz_select_target(const uint8_t *data, std::size_t size, Args &&... args) struct Network; struct Random; +/** + * A Tox_System implementation that consumes fuzzer input to produce network + * inputs and random numbers. Once it runs out of fuzzer input, network receive + * functions return no more data and the random numbers are always zero. + */ struct Fuzz_System { - uint64_t clock; + uint64_t clock = 0; Fuzz_Data &data; std::unique_ptr sys; std::unique_ptr ns; std::unique_ptr rng; - Fuzz_System(Fuzz_Data &input); + explicit Fuzz_System(Fuzz_Data &input); ~Fuzz_System(); }; +/** + * A Tox_System implementation that consumes no fuzzer input but still has a + * working and deterministic RNG. Network receive functions always fail, send + * always succeeds. + */ +struct Null_System { + uint64_t clock = 0; + uint64_t seed = 4; // chosen by fair dice roll. guaranteed to be random. + std::unique_ptr sys; + std::unique_ptr ns; + std::unique_ptr rng; + + Null_System(); + ~Null_System(); +}; + #endif // C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H diff --git a/testing/fuzzing/toxsave_harness.cc b/testing/fuzzing/toxsave_harness.cc index 31b41a88..d380299a 100644 --- a/testing/fuzzing/toxsave_harness.cc +++ b/testing/fuzzing/toxsave_harness.cc @@ -20,7 +20,7 @@ void TestSaveDataLoading(Fuzz_Data &input) const size_t savedata_size = input.size; CONSUME_OR_RETURN(const uint8_t *savedata, input, savedata_size); - Fuzz_System sys(input); + Null_System sys; tox_options_set_operating_system(tox_options, sys.sys.get()); // pass test data to Tox