From d5a70a10772281a95131639966963620efbe532a Mon Sep 17 00:00:00 2001 From: iphydf Date: Sat, 2 Apr 2022 17:10:09 +0000 Subject: [PATCH] test: Add more functionality to the bootstrap harness. Ideally this would be able to reach some of the events, so we can write code to respond to those events, but so far only the friend request event actually happens. --- .../docker/tox-bootstrapd.sha256 | 2 +- testing/fuzzing/BUILD.bazel | 16 +- testing/fuzzing/CMakeLists.txt | 10 +- testing/fuzzing/bootstrap_harness.cc | 143 +++++++++++++++--- testing/fuzzing/fuzz_adapter.c | 89 ----------- testing/fuzzing/fuzz_adapter.h | 44 ------ testing/fuzzing/fuzz_support.cc | 126 ++++++++++++++- testing/fuzzing/fuzz_support.h | 14 +- testing/fuzzing/toxsave_harness.cc | 6 +- toxcore/BUILD.bazel | 5 +- toxcore/ccompat.c | 2 + toxcore/ccompat.h | 17 ++- toxcore/crypto_core.c | 84 +++++----- toxcore/network.c | 107 +++---------- 14 files changed, 361 insertions(+), 304 deletions(-) delete mode 100644 testing/fuzzing/fuzz_adapter.c delete mode 100644 testing/fuzzing/fuzz_adapter.h diff --git a/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 b/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 index 5df2d65f0e..858cc69588 100644 --- a/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 +++ b/other/bootstrap_daemon/docker/tox-bootstrapd.sha256 @@ -1 +1 @@ -b3fb4157d7fc6cd3455f40020bb6b69e5bab4bbdb6ce66d5bc7095146ba5a49e /usr/local/bin/tox-bootstrapd +42f29a351f27d994d14bab0e6288fcb839220af9878ce37a49fbd120b07d16dc /usr/local/bin/tox-bootstrapd diff --git a/testing/fuzzing/BUILD.bazel b/testing/fuzzing/BUILD.bazel index 87cd5725eb..1135a72c5c 100644 --- a/testing/fuzzing/BUILD.bazel +++ b/testing/fuzzing/BUILD.bazel @@ -1,19 +1,18 @@ load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test") -cc_library( - name = "fuzz_adapter", - srcs = ["fuzz_adapter.c"], - hdrs = ["fuzz_adapter.h"], - visibility = ["//c-toxcore:__subpackages__"], -) +package(features = ["layering_check"]) cc_library( name = "fuzz_support", srcs = ["fuzz_support.cc"], hdrs = ["fuzz_support.h"], visibility = ["//c-toxcore:__subpackages__"], - deps = ["//c-toxcore/toxcore:tox"], + deps = [ + "//c-toxcore/toxcore:crypto_core", + "//c-toxcore/toxcore:network", + "//c-toxcore/toxcore:tox", + ], ) cc_library( @@ -31,6 +30,9 @@ cc_fuzz_test( deps = [ ":fuzz_support", "//c-toxcore/toxcore:tox", + "//c-toxcore/toxcore:tox_dispatch", + "//c-toxcore/toxcore:tox_events", + "//c-toxcore/toxcore:util", ], ) diff --git a/testing/fuzzing/CMakeLists.txt b/testing/fuzzing/CMakeLists.txt index 588c130144..5c00c764ec 100644 --- a/testing/fuzzing/CMakeLists.txt +++ b/testing/fuzzing/CMakeLists.txt @@ -2,7 +2,7 @@ target_compile_definitions(toxcore_static PUBLIC "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION") # Override network and random functions -add_library(fuzz_adapter fuzz_adapter.c fuzz_support.cc fuzz_support.h) +add_library(fuzz_support fuzz_support.cc fuzz_support.h) set(LIBFUZZER_LINKER_FLAGS) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") @@ -13,14 +13,14 @@ endif() # Fuzzes the toxsave API add_executable(toxsave_fuzzer toxsave_harness.cc) -target_link_libraries(toxsave_fuzzer toxcore_static fuzz_adapter ${LIBFUZZER_LINKER_FLAGS}) +target_link_libraries(toxsave_fuzzer toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS}) # Fuzzes the bootstrap process add_executable(bootstrap_fuzzer bootstrap_harness.cc) -target_link_libraries(bootstrap_fuzzer toxcore_static fuzz_adapter ${LIBFUZZER_LINKER_FLAGS}) +target_link_libraries(bootstrap_fuzzer toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS}) add_executable(DHT_fuzz_test ../../toxcore/DHT_fuzz_test.cc) -target_link_libraries(DHT_fuzz_test toxcore_static fuzz_adapter ${LIBFUZZER_LINKER_FLAGS}) +target_link_libraries(DHT_fuzz_test toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS}) add_executable(tox_events_fuzz_test ../../toxcore/tox_events_fuzz_test.cc) -target_link_libraries(tox_events_fuzz_test toxcore_static fuzz_adapter ${LIBFUZZER_LINKER_FLAGS}) +target_link_libraries(tox_events_fuzz_test toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS}) diff --git a/testing/fuzzing/bootstrap_harness.cc b/testing/fuzzing/bootstrap_harness.cc index 49869e2955..6d897f3a5d 100644 --- a/testing/fuzzing/bootstrap_harness.cc +++ b/testing/fuzzing/bootstrap_harness.cc @@ -3,23 +3,124 @@ #include #include "../../toxcore/tox.h" +#include "../../toxcore/tox_dispatch.h" +#include "../../toxcore/tox_events.h" #include "../../toxcore/tox_private.h" -#include "fuzz_adapter.h" +#include "../../toxcore/tox_struct.h" +#include "../../toxcore/util.h" #include "fuzz_support.h" +namespace { + +void setup_callbacks(Tox_Dispatch *dispatch) +{ + tox_events_callback_conference_connected( + dispatch, [](Tox *tox, const Tox_Event_Conference_Connected *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_conference_connected( + dispatch, [](Tox *tox, const Tox_Event_Conference_Connected *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_conference_invite( + dispatch, [](Tox *tox, const Tox_Event_Conference_Invite *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_conference_message( + dispatch, [](Tox *tox, const Tox_Event_Conference_Message *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_conference_peer_list_changed(dispatch, + [](Tox *tox, const Tox_Event_Conference_Peer_List_Changed *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_conference_peer_name( + dispatch, [](Tox *tox, const Tox_Event_Conference_Peer_Name *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_conference_title( + dispatch, [](Tox *tox, const Tox_Event_Conference_Title *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_file_chunk_request( + dispatch, [](Tox *tox, const Tox_Event_File_Chunk_Request *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_file_recv( + dispatch, [](Tox *tox, const Tox_Event_File_Recv *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_file_recv_chunk( + dispatch, [](Tox *tox, const Tox_Event_File_Recv_Chunk *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_file_recv_control( + dispatch, [](Tox *tox, const Tox_Event_File_Recv_Control *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_connection_status( + dispatch, [](Tox *tox, const Tox_Event_Friend_Connection_Status *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_lossless_packet( + dispatch, [](Tox *tox, const Tox_Event_Friend_Lossless_Packet *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_lossy_packet( + dispatch, [](Tox *tox, const Tox_Event_Friend_Lossy_Packet *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_message( + dispatch, [](Tox *tox, const Tox_Event_Friend_Message *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_name( + dispatch, [](Tox *tox, const Tox_Event_Friend_Name *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_read_receipt( + dispatch, [](Tox *tox, const Tox_Event_Friend_Read_Receipt *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_request( + dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) { + Tox_Err_Friend_Add err; + tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err); + assert(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY + || err == TOX_ERR_FRIEND_ADD_ALREADY_SENT + || err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM); + }); + tox_events_callback_friend_status( + dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_status_message( + dispatch, [](Tox *tox, const Tox_Event_Friend_Status_Message *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_friend_typing( + dispatch, [](Tox *tox, const Tox_Event_Friend_Typing *event, void *user_data) { + assert(event == nullptr); + }); + tox_events_callback_self_connection_status( + dispatch, [](Tox *tox, const Tox_Event_Self_Connection_Status *event, void *user_data) { + assert(event == nullptr); + }); +} + +} + extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - network_adapter_init(data, size); + Fuzz_Data input{data, size}; - uint64_t clock = 0; - auto sys = fuzz_system(clock); - assert(sys->mono_time_callback != nullptr); - assert(sys->mono_time_user_data != nullptr); + Fuzz_System sys(input); + assert(sys.rng != nullptr); Tox_Options *opts = tox_options_new(nullptr); assert(opts != nullptr); - tox_options_set_operating_system(opts, sys.get()); + tox_options_set_operating_system(opts, sys.sys.get()); Tox_Err_New error_new; Tox *tox = tox_new(opts, &error_new); @@ -34,19 +135,25 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) const bool success = tox_bootstrap(tox, "127.0.0.1", 12345, pub_key, nullptr); assert(success); - /* - * The iteration count here is a magic value in the literal sense, too small - * and coverage will be bad, too big and fuzzing will not be efficient. - * NOTE: This should be fine tuned after gathering some experience. - */ - - for (uint32_t i = 0; i < 50; ++i) { - tox_iterate(tox, nullptr); - // Move the clock forward a decent amount so all the time-based checks - // trigger more quickly. - clock += 200; + tox_events_init(tox); + + Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); + assert(dispatch != nullptr); + setup_callbacks(dispatch); + + while (input.size > 0) { + Tox_Err_Events_Iterate error_iterate; + Tox_Events *events = tox_events_iterate(tox, true, &error_iterate); + assert(tox_events_equal(events, events)); + tox_dispatch_invoke(dispatch, events, tox, nullptr); + tox_events_free(events); + // Move the clock forward a random amount so all the time-based checks + // trigger more quickly. Move by at least 20ms (iteration interval) so + // at least something happens. + sys.clock += max_u16(20, random_u08(sys.rng.get())); } + tox_dispatch_free(dispatch); tox_kill(tox); return 0; // Non-zero return values are reserved for future use. } diff --git a/testing/fuzzing/fuzz_adapter.c b/testing/fuzzing/fuzz_adapter.c deleted file mode 100644 index 82fd64534c..0000000000 --- a/testing/fuzzing/fuzz_adapter.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "fuzz_adapter.h" - -struct fuzz_buf { - /* Fuzz data buffer */ - const uint8_t *cur; - const uint8_t *end; -}; - -static struct fuzz_buf data; - -#include -#include -#include - - -void network_adapter_init(const uint8_t *buf, size_t length) -{ - data.cur = buf; - data.end = buf + length; -} - -ssize_t fuzz_sendto(int sockfd, const void *buf, size_t len, - int flags, const struct sockaddr *addr, - socklen_t addrlen) -{ - return len; -} - -ssize_t fuzz_send(int sockfd, const void *buf, size_t len, int flags) -{ - return len; -} - -static ssize_t recv_common(void *buf, size_t buf_len) -{ - if (data.cur + 2 >= data.end) { - return -1; - } - - uint16_t fuzz_len = (data.cur[0] << 8) | data.cur[1]; - data.cur += 2; - - size_t available = data.end - data.cur; - - size_t res = fuzz_len > available ? available : fuzz_len; - res = buf_len > res ? res : buf_len; - - memcpy(buf, data.cur, res); - data.cur += res; - - return res; -} - -ssize_t fuzz_recvfrom(int sockfd, void *buf, size_t len, - int flags, struct sockaddr *src_addr, - socklen_t *addr_len) -{ - if (src_addr && addr_len && (sizeof(struct sockaddr) <= *addr_len)) { - *src_addr = (struct sockaddr) { - 0 - }; - // Dummy Addr - src_addr->sa_family = AF_INET; - - // We want an AF_INET address with dummy values - struct sockaddr_in *addr_in = (struct sockaddr_in *)(void *)src_addr; - addr_in->sin_port = 12356; - addr_in->sin_addr.s_addr = INADDR_LOOPBACK + 1; - *addr_len = sizeof(struct sockaddr); - } - - return recv_common(buf, len); -} - -ssize_t fuzz_recv(int sockfd, void *buf, size_t len, int flags) -{ - return recv_common(buf, len); -} - -void fuzz_random_bytes(uint8_t *rnd, size_t length) -{ - // Amount of data is limited - size_t available = data.end - data.cur; - size_t bytes_read = length > available ? available : length; - // Initialize everything to make MSAN and others happy - memset(rnd, 0, length); - memcpy(rnd, data.cur, bytes_read); - data.cur += bytes_read; -} diff --git a/testing/fuzzing/fuzz_adapter.h b/testing/fuzzing/fuzz_adapter.h deleted file mode 100644 index 91fdbc7680..0000000000 --- a/testing/fuzzing/fuzz_adapter.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later - * Copyright © 2021 The TokTok team. - */ - -#ifndef C_TOXCORE_TESTING_FUZZING_FUZZ_ADAPTER_H -#define C_TOXCORE_TESTING_FUZZING_FUZZ_ADAPTER_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Init function for the fuzzing harness - * @param buf Begin of fuzz data - * @param length Length of buf - */ -void network_adapter_init(const uint8_t *buf, size_t length); - -/* The following functions intercept calls to standard network functions for fuzzing purposes and return data from the fuzz buffer. */ - -ssize_t fuzz_sendto(int sockfd, const void *buf, size_t len, - int flags, const struct sockaddr *addr, - socklen_t addrlen); - -ssize_t fuzz_send(int sockfd, const void *buf, size_t len, int flags); - -ssize_t fuzz_recvfrom(int sockfd, void *buf, size_t len, - int flags, struct sockaddr *src_addr, - socklen_t *addr_len); - -ssize_t fuzz_recv(int sockfd, void *buf, size_t len, int flags); - -/* The following functions intercept generation of random data */ -void fuzz_random_bytes(uint8_t *rnd, size_t length); - -#ifdef __cplusplus -} -#endif - -#endif // C_TOXCORE_TESTING_FUZZING_FUZZ_ADAPTER_H diff --git a/testing/fuzzing/fuzz_support.cc b/testing/fuzzing/fuzz_support.cc index b3e8ed3227..761951a279 100644 --- a/testing/fuzzing/fuzz_support.cc +++ b/testing/fuzzing/fuzz_support.cc @@ -4,18 +4,130 @@ #include "fuzz_support.h" +#include +#include + +#include #include #include "../../toxcore/crypto_core.h" #include "../../toxcore/network.h" #include "../../toxcore/tox_private.h" -std::unique_ptr fuzz_system(uint64_t &clock) +// TODO(iphydf): Put this somewhere shared. +struct Network_Addr { + struct sockaddr_storage addr; + size_t size; +}; + +static int recv_common(Fuzz_Data &input, void *buf, size_t buf_len) { - auto sys = std::make_unique(); - sys->mono_time_callback = [](void *user_data) { return *static_cast(user_data); }; - sys->mono_time_user_data = &clock; - sys->rng = system_random(); // TODO(iphydf): Put fuzz_random here. - sys->ns = system_network(); // TODO(iphydf): Put fuzz_network here. - return sys; + if (input.size < 2) { + return -1; + } + + uint16_t fuzz_len = (input.data[0] << 8) | input.data[1]; + input.data += 2; + input.size -= 2; + + size_t available = input.size; + + size_t res = fuzz_len > available ? available : fuzz_len; + res = buf_len > res ? res : buf_len; + + memcpy(buf, input.data, res); + input.data += res; + input.size -= res; + + return res; } + +static const Network_Funcs fuzz_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 = + [](void *obj, int sock) { + // TODO(iphydf): Return something sensible here (from the fuzzer): number of + // bytes to be read from the socket. + return 0; + }, + .recv = + [](void *obj, int sock, uint8_t *buf, size_t len) { + // Receive data from the fuzzer. + return recv_common(static_cast(obj)->data, buf, len); + }, + .recvfrom = + [](void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr) { + addr->addr = sockaddr_storage{}; + // Dummy Addr + addr->addr.ss_family = AF_INET; + + // We want an AF_INET address with dummy values + sockaddr_in *addr_in = reinterpret_cast(&addr->addr); + addr_in->sin_port = 12356; + addr_in->sin_addr.s_addr = INADDR_LOOPBACK + 1; + addr->size = sizeof(struct sockaddr); + + return recv_common(static_cast(obj)->data, buf, len); + }, + .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 const Random_Funcs fuzz_random_funcs = { + .random_bytes = + [](void *obj, uint8_t *bytes, size_t length) { + Fuzz_System *sys = static_cast(obj); + // Amount of data is limited + size_t available = sys->data.size; + size_t bytes_read = length > available ? available : length; + // Initialize everything to make MSAN and others happy + std::memset(bytes, 0, length); + std::memcpy(bytes, sys->data.data, bytes_read); + sys->data.data += bytes_read; + sys->data.size -= bytes_read; + }, + .random_uniform = + [](void *obj, uint32_t upper_bound) { + Fuzz_System *sys = static_cast(obj); + uint32_t randnum; + sys->rng->funcs->random_bytes( + sys, reinterpret_cast(&randnum), sizeof(randnum)); + return randnum % upper_bound; + }, +}; + +Fuzz_System::Fuzz_System(Fuzz_Data &input) + : clock(0) + , data(input) + , sys(std::make_unique()) + , ns(std::make_unique(Network{&fuzz_network_funcs, this})) + , rng(std::make_unique(Random{&fuzz_random_funcs, this})) +{ + sys->mono_time_callback + = [](void *user_data) { return static_cast(user_data)->clock; }; + sys->mono_time_user_data = this; + sys->ns = ns.get(); + sys->rng = rng.get(); +} + +Fuzz_System::~Fuzz_System() { } diff --git a/testing/fuzzing/fuzz_support.h b/testing/fuzzing/fuzz_support.h index a8a1d8dab7..b25a8076a1 100644 --- a/testing/fuzzing/fuzz_support.h +++ b/testing/fuzzing/fuzz_support.h @@ -97,6 +97,18 @@ void fuzz_select_target(const uint8_t *data, std::size_t size, Args &&... args) return fuzz_select_target(selector, input, std::forward(args)...); } -std::unique_ptr fuzz_system(uint64_t &clock); +struct Network; +struct Random; + +struct Fuzz_System { + uint64_t clock; + Fuzz_Data &data; + std::unique_ptr sys; + std::unique_ptr ns; + std::unique_ptr rng; + + Fuzz_System(Fuzz_Data &input); + ~Fuzz_System(); +}; #endif // C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H diff --git a/testing/fuzzing/toxsave_harness.cc b/testing/fuzzing/toxsave_harness.cc index 068c9d9a97..4020a0b540 100644 --- a/testing/fuzzing/toxsave_harness.cc +++ b/testing/fuzzing/toxsave_harness.cc @@ -16,9 +16,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) assert(tox_options != nullptr); assert(error_options == TOX_ERR_OPTIONS_NEW_OK); - uint64_t clock = 0; - auto sys = fuzz_system(clock); - tox_options_set_operating_system(tox_options, sys.get()); + Fuzz_Data input{data + size, 0}; // empty data, since we use it all for savedata. + Fuzz_System sys(input); + tox_options_set_operating_system(tox_options, sys.sys.get()); // pass test data to Tox tox_options_set_savedata_data(tox_options, data, size); diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel index c852eb0580..de7229b708 100644 --- a/toxcore/BUILD.bazel +++ b/toxcore/BUILD.bazel @@ -64,7 +64,6 @@ cc_library( visibility = ["//c-toxcore:__subpackages__"], deps = [ ":ccompat", - "//c-toxcore/testing/fuzzing:fuzz_adapter", "@libsodium", ], ) @@ -136,7 +135,6 @@ cc_library( ], deps = [ ":ccompat", - "//c-toxcore/testing/fuzzing:fuzz_adapter", "@pthread", ], ) @@ -160,6 +158,7 @@ cc_library( "//c-toxcore/auto_tests:__pkg__", "//c-toxcore/other:__pkg__", "//c-toxcore/other/bootstrap_daemon:__pkg__", + "//c-toxcore/testing/fuzzing:__pkg__", "//c-toxcore/toxav:__pkg__", ], deps = [ @@ -178,6 +177,7 @@ cc_library( "//c-toxcore/auto_tests:__pkg__", "//c-toxcore/other:__pkg__", "//c-toxcore/other/bootstrap_daemon:__pkg__", + "//c-toxcore/testing/fuzzing:__pkg__", "//c-toxcore/toxav:__pkg__", ], deps = [ @@ -186,7 +186,6 @@ cc_library( ":logger", ":mono_time", ":util", - "//c-toxcore/testing/fuzzing:fuzz_adapter", "@libsodium", "@psocket", "@pthread", diff --git a/toxcore/ccompat.c b/toxcore/ccompat.c index 30e689d06d..30e90b9935 100644 --- a/toxcore/ccompat.c +++ b/toxcore/ccompat.c @@ -2,3 +2,5 @@ * Copyright © 2022 The TokTok team. */ #include "ccompat.h" + +const bool tox_is_fuzzing = TOX_IS_FUZZING; diff --git a/toxcore/ccompat.h b/toxcore/ccompat.h index 8cd2844c35..11dd413c29 100644 --- a/toxcore/ccompat.h +++ b/toxcore/ccompat.h @@ -8,11 +8,26 @@ #ifndef C_TOXCORE_TOXCORE_CCOMPAT_H #define C_TOXCORE_TOXCORE_CCOMPAT_H +#include // bool, false, true #include // NULL, size_t #include "attributes.h" -/* No declarations here. */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +#define TOX_IS_FUZZING true +#else +#define TOX_IS_FUZZING false +#endif + +extern const bool tox_is_fuzzing; + +#ifdef __cplusplus +} // extern "C" +#endif //!TOKSTYLE- diff --git a/toxcore/crypto_core.c b/toxcore/crypto_core.c index 5b360bdc45..b65b7607e5 100644 --- a/toxcore/crypto_core.c +++ b/toxcore/crypto_core.c @@ -40,12 +40,6 @@ #define ENC_SECRET_KEY_SIZE CRYPTO_SECRET_KEY_SIZE #endif -//!TOKSTYLE- -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -#include "../testing/fuzzing/fuzz_adapter.h" -#endif -//!TOKSTYLE+ - static_assert(CRYPTO_PUBLIC_KEY_SIZE == crypto_box_PUBLICKEYBYTES, "CRYPTO_PUBLIC_KEY_SIZE should be equal to crypto_box_PUBLICKEYBYTES"); static_assert(CRYPTO_SECRET_KEY_SIZE == crypto_box_SECRETKEYBYTES, @@ -122,38 +116,38 @@ static void crypto_free(uint8_t *ptr, size_t bytes) void crypto_memzero(void *data, size_t length) { -#ifndef VANILLA_NACL - sodium_memzero(data, length); -#else +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL) memset(data, 0, length); +#else + sodium_memzero(data, length); #endif } bool crypto_memlock(void *data, size_t length) { -#ifndef VANILLA_NACL +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL) + return false; +#else if (sodium_mlock(data, length) != 0) { return false; } return true; -#else - return false; #endif } bool crypto_memunlock(void *data, size_t length) { -#ifndef VANILLA_NACL +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL) + return false; +#else if (sodium_munlock(data, length) != 0) { return false; } return true; -#else - return false; #endif } @@ -169,18 +163,26 @@ bool public_key_eq(const uint8_t *pk1, const uint8_t *pk2) bool crypto_sha512_eq(const uint8_t *cksum1, const uint8_t *cksum2) { -#ifndef VANILLA_NACL - return crypto_verify_64(cksum1, cksum2) == 0; -#else +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + // Hope that this is better for the fuzzer + return memcmp(cksum1, cksum2, CRYPTO_SHA512_SIZE) == 0; +#elif defined(VANILLA_NACL) const int lo = crypto_verify_32(cksum1, cksum2) == 0 ? 1 : 0; const int hi = crypto_verify_32(cksum1 + 8, cksum2 + 8) == 0 ? 1 : 0; return (lo & hi) == 1; +#else + return crypto_verify_64(cksum1, cksum2) == 0; #endif } bool crypto_sha256_eq(const uint8_t *cksum1, const uint8_t *cksum2) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // Hope that this is better for the fuzzer + return memcmp(cksum1, cksum2, CRYPTO_SHA256_SIZE) == 0; +#else return crypto_verify_32(cksum1, cksum2) == 0; +#endif } uint8_t random_u08(const Random *rng) @@ -238,17 +240,19 @@ bool crypto_signature_verify(const uint8_t *signature, const uint8_t *message, u bool public_key_valid(const uint8_t *public_key) { - if (public_key[31] >= 128) { /* Last bit of key is always zero. */ - return false; - } - - return true; + /* Last bit of key is always zero. */ + return public_key[31] < 128; } int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *shared_key) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + memcpy(shared_key, public_key, CRYPTO_SHARED_KEY_SIZE); + return 0; +#else return crypto_box_beforenm(shared_key, public_key, secret_key); +#endif } int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, @@ -450,11 +454,6 @@ void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key) crypto_scalarmult_curve25519_base(public_key, secret_key); } -void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length) -{ - crypto_hash_sha256(hash, data, length); -} - void new_hmac_key(const Random *rng, uint8_t *key) { random_bytes(rng, key, CRYPTO_HMAC_KEY_SIZE); @@ -472,31 +471,36 @@ bool crypto_hmac_verify(const uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[ return crypto_auth_verify(auth, data, length, key) == 0; } +void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length) +{ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + memset(hash, 0, CRYPTO_SHA256_SIZE); + memcpy(hash, data, length < CRYPTO_SHA256_SIZE ? length : CRYPTO_SHA256_SIZE); +#else + crypto_hash_sha256(hash, data, length); +#endif +} + void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + memset(hash, 0, CRYPTO_SHA512_SIZE); + memcpy(hash, data, length < CRYPTO_SHA512_SIZE ? length : CRYPTO_SHA512_SIZE); +#else crypto_hash_sha512(hash, data, length); +#endif } non_null() static void sys_random_bytes(void *obj, uint8_t *bytes, size_t length) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - fuzz_random_bytes(bytes, length); -#else randombytes(bytes, length); -#endif } non_null() static uint32_t sys_random_uniform(void *obj, uint32_t upper_bound) { -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(VANILLA_NACL) - uint32_t randnum; - sys_random_bytes(obj, (uint8_t *)&randnum, sizeof(randnum)); - return randnum % upper_bound; -#else return randombytes_uniform(upper_bound); -#endif // VANILLA_NACL } static const Random_Funcs system_random_funcs = { @@ -515,7 +519,9 @@ const Random *system_random(void) return nullptr; } #endif - + if (TOX_IS_FUZZING) { + return nullptr; + } return &system_random_obj; } diff --git a/toxcore/network.c b/toxcore/network.c index c6cb60bbc0..f73fb08786 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -97,12 +97,6 @@ #include "mono_time.h" #include "util.h" -//!TOKSTYLE- -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -#include "../testing/fuzzing/fuzz_adapter.h" -#endif -//!TOKSTYLE+ - // Disable MSG_NOSIGNAL on systems not supporting it, e.g. Windows, FreeBSD #if !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 @@ -127,12 +121,10 @@ static bool should_ignore_recv_error(int err) return err == EWOULDBLOCK; } -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION static bool should_ignore_connect_error(int err) { return err == EWOULDBLOCK || err == EINPROGRESS; } -#endif non_null() static const char *inet_ntop4(const struct in_addr *addr, char *buf, size_t bufsize) @@ -483,54 +475,34 @@ struct Network_Addr { non_null() static int sys_close(void *obj, int sock) { -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) - return 0; -#elif defined(OS_WIN32) +#if defined(OS_WIN32) return closesocket(sock); #else // !OS_WIN32 return close(sock); -#endif // FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +#endif } non_null() static int sys_accept(void *obj, int sock) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 2; -#else return accept(sock, nullptr, nullptr); -#endif } non_null() static int sys_bind(void *obj, int sock, const Network_Addr *addr) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 0; -#else return bind(sock, (const struct sockaddr *)&addr->addr, addr->size); -#endif } non_null() static int sys_listen(void *obj, int sock, int backlog) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 0; -#else return listen(sock, backlog); -#endif } non_null() static int sys_recvbuf(void *obj, int sock) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - // TODO(iphydf): Return something sensible here (from the fuzzer): number of - // bytes to be read from the socket. - return 0; -#else - #ifdef OS_WIN32 u_long count = 0; ioctlsocket(sock, FIONREAD, &count); @@ -540,100 +512,63 @@ static int sys_recvbuf(void *obj, int sock) #endif return count; -#endif } non_null() static int sys_recv(void *obj, int sock, uint8_t *buf, size_t len) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return fuzz_recv(sock, (char *)buf, len, MSG_NOSIGNAL); -#else return recv(sock, (char *)buf, len, MSG_NOSIGNAL); -#endif } non_null() static int sys_send(void *obj, int sock, const uint8_t *buf, size_t len) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return fuzz_send(sock, (const char *)buf, len, MSG_NOSIGNAL); -#else return send(sock, (const char *)buf, len, MSG_NOSIGNAL); -#endif } non_null() static int sys_sendto(void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return fuzz_sendto(sock, (const char *)buf, len, 0, (const struct sockaddr *)&addr->addr, addr->size); -#else return sendto(sock, (const char *)buf, len, 0, (const struct sockaddr *)&addr->addr, addr->size); -#endif } non_null() static int sys_recvfrom(void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - socklen_t size = addr->size; - const int ret = fuzz_recvfrom(sock, (char *)buf, len, 0, (struct sockaddr *)&addr->addr, &size); - addr->size = size; - return ret; -#else socklen_t size = addr->size; const int ret = recvfrom(sock, (char *)buf, len, 0, (struct sockaddr *)&addr->addr, &size); addr->size = size; return ret; -#endif } non_null() static int sys_socket(void *obj, int domain, int type, int proto) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 1; -#else return (int)socket(domain, type, proto); -#endif } non_null() static int sys_socket_nonblock(void *obj, int sock, bool nonblock) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 0; -#else #ifdef OS_WIN32 u_long mode = nonblock ? 1 : 0; return ioctlsocket(sock, FIONBIO, &mode); #else return fcntl(sock, F_SETFL, O_NONBLOCK, nonblock ? 1 : 0); #endif /* OS_WIN32 */ -#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ } non_null() static int sys_getsockopt(void *obj, int sock, int level, int optname, void *optval, size_t *optlen) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - memset(optval, 0, *optlen); - return 0; -#else socklen_t len = *optlen; const int ret = getsockopt(sock, level, optname, optval, &len); *optlen = len; return ret; -#endif } non_null() static int sys_setsockopt(void *obj, int sock, int level, int optname, const void *optval, size_t optlen) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 0; -#else return setsockopt(sock, level, optname, optval, optlen); -#endif } static const Network_Funcs system_network_funcs = { @@ -662,6 +597,9 @@ const Network *system_network(void) return nullptr; } #endif + if (TOX_IS_FUZZING) { + return nullptr; + } return &system_network_obj; } @@ -1521,11 +1459,9 @@ bool addr_parse_ip(const char *address, IP *to) return false; } -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /** addr_resolve return values */ #define TOX_ADDR_RESOLVE_INET 1 #define TOX_ADDR_RESOLVE_INET6 2 -#endif /** * Uses getaddrinfo to resolve an address into an IP address. @@ -1547,9 +1483,9 @@ bool addr_parse_ip(const char *address, IP *to) non_null(1, 2, 3) nullable(4) static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extra) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 0; -#else + if (TOX_IS_FUZZING) { + return 0; + } if (address == nullptr || to == nullptr) { return 0; @@ -1634,7 +1570,6 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr freeaddrinfo(server); return result; -#endif } bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra) @@ -1674,9 +1609,10 @@ bool net_connect(const Logger *log, Socket sock, const IP_Port *ip_port) return false; } -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return addrsize != 0; -#else + if (TOX_IS_FUZZING) { + return true; + } + Ip_Ntoa ip_str; LOGGER_DEBUG(log, "connecting socket %d to %s:%d", (int)sock.sock, net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port)); @@ -1696,20 +1632,20 @@ bool net_connect(const Logger *log, Socket sock, const IP_Port *ip_port) } return true; -#endif } int32_t net_getipport(const char *node, IP_Port **res, int tox_type) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - *res = (IP_Port *)calloc(1, sizeof(IP_Port)); - assert(*res != nullptr); - IP_Port *ip_port = *res; - ip_port->ip.ip.v4.uint32 = 0x7F000003; // 127.0.0.3 - ip_port->ip.family = *make_tox_family(AF_INET); + if (TOX_IS_FUZZING) { + *res = (IP_Port *)calloc(1, sizeof(IP_Port)); + assert(*res != nullptr); + IP_Port *ip_port = *res; + ip_port->ip.ip.v4.uint32 = 0x7F000003; // 127.0.0.3 + ip_port->ip.family = *make_tox_family(AF_INET); + + return 1; + } - return 1; -#else // Try parsing as IP address first. IP_Port parsed = {{{0}}}; @@ -1798,7 +1734,6 @@ int32_t net_getipport(const char *node, IP_Port **res, int tox_type) freeaddrinfo(infos); return count; -#endif } void net_freeipport(IP_Port *ip_ports)