test: Add fuzz tests to the coverage run.

So we don't need to write so many edge case tests ourselves for things
like parsers, which really don't need those manual tests, as long as we
can check for some properties like "can output the parsed data and it'll
be the same as the input".
This commit is contained in:
iphydf 2024-01-11 15:24:02 +00:00
parent df76f5cf47
commit 50f1b30fa9
No known key found for this signature in database
GPG Key ID: 3855DBA2D74403C9
9 changed files with 69 additions and 64 deletions

View File

@ -160,21 +160,7 @@ if(BOOTSTRAP_DAEMON AND WIN32)
set(BOOTSTRAP_DAEMON OFF) set(BOOTSTRAP_DAEMON OFF)
endif() endif()
# Enabling this breaks all other tests and no network connections will be possible
option(BUILD_FUZZ_TESTS "Build fuzzing harnesses" OFF) option(BUILD_FUZZ_TESTS "Build fuzzing harnesses" OFF)
if(BUILD_FUZZ_TESTS)
message(STATUS "Building in fuzz testing mode, no network connection will be possible")
# Disable everything we can
set(AUTOTEST OFF)
set(BUILD_MISC_TESTS OFF)
set(BUILD_FUN_UTILS OFF)
set(ENABLE_SHARED OFF)
set(MUST_BUILD_TOXAV OFF)
set(BUILD_TOXAV OFF)
set(BOOTSTRAP_DAEMON OFF)
set(DHT_BOOTSTRAP OFF)
endif()
if(MSVC) if(MSVC)
option(MSVC_STATIC_SODIUM "Whether to link libsodium statically for MSVC" OFF) option(MSVC_STATIC_SODIUM "Whether to link libsodium statically for MSVC" OFF)
@ -448,20 +434,33 @@ endif()
################################################################################ ################################################################################
# Create combined library from all the sources. # Create combined library from all the sources.
add_module(toxcore ${toxcore_SOURCES}) if(ENABLE_SHARED)
add_library(toxcore_shared SHARED ${toxcore_SOURCES})
set_target_properties(toxcore_shared PROPERTIES OUTPUT_NAME toxcore)
target_link_libraries(toxcore_shared PRIVATE ${toxcore_LINK_LIBRARIES})
target_link_directories(toxcore_shared PUBLIC ${toxcore_LINK_DIRECTORIES})
target_include_directories(toxcore_shared SYSTEM PRIVATE ${toxcore_INCLUDE_DIRECTORIES})
target_compile_options(toxcore_shared PRIVATE ${toxcore_COMPILE_OPTIONS})
endif()
# Link it to all dependencies. if(ENABLE_STATIC)
if(TARGET toxcore_static) add_library(toxcore_static STATIC ${toxcore_SOURCES})
if(NOT MSVC)
set_target_properties(toxcore_static PROPERTIES OUTPUT_NAME toxcore)
endif()
target_link_libraries(toxcore_static PRIVATE ${toxcore_LINK_LIBRARIES}) target_link_libraries(toxcore_static PRIVATE ${toxcore_LINK_LIBRARIES})
target_link_directories(toxcore_static PUBLIC ${toxcore_LINK_DIRECTORIES}) target_link_directories(toxcore_static PUBLIC ${toxcore_LINK_DIRECTORIES})
target_include_directories(toxcore_static SYSTEM PRIVATE ${toxcore_INCLUDE_DIRECTORIES}) target_include_directories(toxcore_static SYSTEM PRIVATE ${toxcore_INCLUDE_DIRECTORIES})
target_compile_options(toxcore_static PRIVATE ${toxcore_COMPILE_OPTIONS}) target_compile_options(toxcore_static PRIVATE ${toxcore_COMPILE_OPTIONS})
endif() endif()
if(TARGET toxcore_shared)
target_link_libraries(toxcore_shared PRIVATE ${toxcore_LINK_LIBRARIES}) if(BUILD_FUZZ_TESTS)
target_link_directories(toxcore_shared PUBLIC ${toxcore_LINK_DIRECTORIES}) add_library(toxcore_fuzz STATIC ${toxcore_SOURCES})
target_include_directories(toxcore_shared SYSTEM PRIVATE ${toxcore_INCLUDE_DIRECTORIES}) target_link_libraries(toxcore_fuzz PRIVATE ${toxcore_LINK_LIBRARIES})
target_compile_options(toxcore_shared PRIVATE ${toxcore_COMPILE_OPTIONS}) target_link_directories(toxcore_fuzz PUBLIC ${toxcore_LINK_DIRECTORIES})
target_include_directories(toxcore_fuzz SYSTEM PRIVATE ${toxcore_INCLUDE_DIRECTORIES})
target_compile_options(toxcore_fuzz PRIVATE ${toxcore_COMPILE_OPTIONS})
target_compile_definitions(toxcore_fuzz PUBLIC "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
endif() endif()
# Make version script (on systems that support it) to limit symbol visibility. # Make version script (on systems that support it) to limit symbol visibility.

View File

@ -19,19 +19,6 @@ if(FULLY_STATIC)
set(ENABLE_STATIC ON) set(ENABLE_STATIC ON)
endif() endif()
function(add_module lib)
if(ENABLE_SHARED)
add_library(${lib}_shared SHARED ${ARGN})
set_target_properties(${lib}_shared PROPERTIES OUTPUT_NAME ${lib})
endif()
if(ENABLE_STATIC)
add_library(${lib}_static STATIC ${ARGN})
if(NOT MSVC)
set_target_properties(${lib}_static PROPERTIES OUTPUT_NAME ${lib})
endif()
endif()
endfunction()
function(install_module lib) function(install_module lib)
if(TARGET ${lib}_shared) if(TARGET ${lib}_shared)
set_target_properties(${lib}_shared PROPERTIES set_target_properties(${lib}_shared PROPERTIES

View File

@ -31,8 +31,8 @@ out = (subprocess.run(
errors = 0 errors = 0
for line in out.split("\n"): for line in out.split("\n"):
# other/fun can do what it wants. # other/fun and mallocfail can do what they want.
if "/fun/" in line: if "/fun/" in line or "/mallocfail/" in line:
continue continue
filename, include = line.split(":", 1) filename, include = line.split(":", 1)
# We only check headers. # We only check headers.

View File

@ -60,6 +60,7 @@ RUN source .github/scripts/flags-coverage.sh \
-DSTRICT_ABI=ON \ -DSTRICT_ABI=ON \
-DAUTOTEST=ON \ -DAUTOTEST=ON \
-DPROXY_TEST=ON \ -DPROXY_TEST=ON \
-DBUILD_FUZZ_TESTS=ON \
-DUSE_IPV6=OFF \ -DUSE_IPV6=OFF \
-DTEST_TIMEOUT_SECONDS=40 \ -DTEST_TIMEOUT_SECONDS=40 \
&& cmake --build _build --parallel 8 --target install && cmake --build _build --parallel 8 --target install

View File

@ -1,26 +1,33 @@
# For coverage tests
target_compile_definitions(toxcore_static PUBLIC "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
# Override network and random functions # Override network and random functions
add_library(fuzz_support func_conversion.h fuzz_support.cc fuzz_support.h) add_library(fuzz_support func_conversion.h fuzz_support.cc fuzz_support.h)
set(LIBFUZZER_LINKER_FLAGS) set(LIBFUZZER_LINKER_FLAGS)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(LIBFUZZER_LINKER_FLAGS "-fsanitize=fuzzer") set(LIBFUZZER_LINKER_FLAGS "-fsanitize=fuzzer")
else() else()
message(SEND_ERROR "Compiler must be Clang to build fuzz targets") message(SEND_ERROR "Compiler must be Clang to build fuzz targets")
endif() endif()
function(fuzz_test target source_dir)
set(${target}_CORPUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/toktok-fuzzer/corpus/${target}_fuzz_test)
file(GLOB ${target}_fuzz_CORPUS "${${target}_CORPUS_DIR}/*")
add_executable(${target}_fuzz_test ${source_dir}/${target}_fuzz_test.cc)
target_link_libraries(${target}_fuzz_test PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
if(${target}_fuzz_CORPUS)
add_test(NAME ${target}_fuzz COMMAND ${CROSSCOMPILING_EMULATOR} ${target}_fuzz_test -max_total_time=10 ${${target}_fuzz_CORPUS})
endif()
endfunction()
# Fuzzes the toxsave API # Fuzzes the toxsave API
add_executable(toxsave_fuzzer toxsave_harness.cc) add_executable(toxsave_fuzzer toxsave_harness.cc)
target_link_libraries(toxsave_fuzzer PRIVATE toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS}) target_link_libraries(toxsave_fuzzer PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
# Fuzzes the bootstrap process # Fuzzes the bootstrap process
add_executable(bootstrap_fuzzer bootstrap_harness.cc) add_executable(bootstrap_fuzzer bootstrap_harness.cc)
target_link_libraries(bootstrap_fuzzer PRIVATE toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS}) target_link_libraries(bootstrap_fuzzer PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
add_executable(DHT_fuzz_test ../../toxcore/DHT_fuzz_test.cc) fuzz_test(DHT ../../toxcore)
target_link_libraries(DHT_fuzz_test PRIVATE toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS}) fuzz_test(forwarding ../../toxcore)
fuzz_test(group_announce ../../toxcore)
add_executable(tox_events_fuzz_test ../../toxcore/tox_events_fuzz_test.cc) fuzz_test(group_moderation ../../toxcore)
target_link_libraries(tox_events_fuzz_test PRIVATE toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS}) fuzz_test(tox_events ../../toxcore)

View File

@ -7,6 +7,7 @@
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <deque> #include <deque>
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
@ -28,13 +29,20 @@ struct Fuzz_Data {
Fuzz_Data &operator=(const Fuzz_Data &rhs) = delete; Fuzz_Data &operator=(const Fuzz_Data &rhs) = delete;
Fuzz_Data(const Fuzz_Data &rhs) = delete; Fuzz_Data(const Fuzz_Data &rhs) = delete;
uint8_t consume1() struct Consumer {
{ Fuzz_Data &fd;
const uint8_t val = data[0];
++data; template <typename T>
--size; operator T()
return val; {
} const uint8_t *bytes = fd.consume(sizeof(T));
T val;
std::memcpy(&val, bytes, sizeof(T));
return val;
}
};
Consumer consume1() { return Consumer{*this}; }
const uint8_t *consume(std::size_t count) const uint8_t *consume(std::size_t count)
{ {

View File

@ -88,6 +88,7 @@ cc_test(
srcs = ["util_test.cc"], srcs = ["util_test.cc"],
deps = [ deps = [
":crypto_core", ":crypto_core",
":crypto_core_test_util",
":util", ":util",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",

View File

@ -12,7 +12,8 @@ namespace {
void TestUnpackAnnouncesList(Fuzz_Data &input) void TestUnpackAnnouncesList(Fuzz_Data &input)
{ {
CONSUME1_OR_RETURN(const uint8_t max_count, input); CONSUME1_OR_RETURN(const uint8_t max_count, input);
std::vector<GC_Announce> announces(max_count); // Always allocate at least something to avoid passing nullptr to functions below.
std::vector<GC_Announce> announces(max_count + 1);
// TODO(iphydf): How do we know the packed size? // TODO(iphydf): How do we know the packed size?
CONSUME1_OR_RETURN(const uint16_t packed_size, input); CONSUME1_OR_RETURN(const uint16_t packed_size, input);
@ -20,10 +21,11 @@ void TestUnpackAnnouncesList(Fuzz_Data &input)
Logger *logger = logger_new(); Logger *logger = logger_new();
if (gca_unpack_announces_list(logger, input.data, input.size, announces.data(), max_count) if (gca_unpack_announces_list(logger, input.data, input.size, announces.data(), max_count)
!= -1) { != -1) {
std::vector<uint8_t> packed(packed_size); // Always allocate at least something to avoid passing nullptr to functions below.
std::vector<uint8_t> packed(packed_size + 1);
size_t processed; size_t processed;
gca_pack_announces_list( gca_pack_announces_list(
logger, packed.data(), packed.size(), announces.data(), announces.size(), &processed); logger, packed.data(), packed_size, announces.data(), max_count, &processed);
} }
logger_kill(logger); logger_kill(logger);
} }
@ -37,8 +39,9 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
Logger *logger = logger_new(); Logger *logger = logger_new();
if (gca_unpack_public_announce(logger, input.data, input.size, &public_announce) != -1) { if (gca_unpack_public_announce(logger, input.data, input.size, &public_announce) != -1) {
std::vector<uint8_t> packed(packed_size); // Always allocate at least something to avoid passing nullptr to functions below.
gca_pack_public_announce(logger, packed.data(), packed.size(), &public_announce); std::vector<uint8_t> packed(packed_size + 1);
gca_pack_public_announce(logger, packed.data(), packed_size, &public_announce);
} }
logger_kill(logger); logger_kill(logger);
} }

View File

@ -3,13 +3,13 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "crypto_core.h" #include "crypto_core.h"
#include "crypto_core_test_util.hh"
namespace { namespace {
TEST(Util, TwoRandomIdsAreNotEqual) TEST(Util, TwoRandomIdsAreNotEqual)
{ {
const Random *rng = system_random(); Test_Random rng;
ASSERT_NE(rng, nullptr);
uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t sk1[CRYPTO_SECRET_KEY_SIZE]; uint8_t sk1[CRYPTO_SECRET_KEY_SIZE];
uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE];
@ -23,8 +23,7 @@ TEST(Util, TwoRandomIdsAreNotEqual)
TEST(Util, IdCopyMakesKeysEqual) TEST(Util, IdCopyMakesKeysEqual)
{ {
const Random *rng = system_random(); Test_Random rng;
ASSERT_NE(rng, nullptr);
uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t pk1[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t sk1[CRYPTO_SECRET_KEY_SIZE]; uint8_t sk1[CRYPTO_SECRET_KEY_SIZE];
uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE] = {0}; uint8_t pk2[CRYPTO_PUBLIC_KEY_SIZE] = {0};