Merge commit 'b1fe0644843f5d08cd203bb5d4cdb923172f247b'
This commit is contained in:
@ -4,4 +4,4 @@
|
||||
cd ../
|
||||
|
||||
# Run code coverage only on minized corpus to save time
|
||||
afl-cov --cover-corpus -d ./_afl_out --overwrite --live --coverage-cmd "_cov_build/bootstrap_fuzzer @@" --code-dir ../
|
||||
afl-cov --cover-corpus -d ./_afl_out --overwrite --live --coverage-cmd "_cov_build/bootstrap_fuzz_test @@" --code-dir ../
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
HARNESS_BIN="../_afl_build/bootstrap_fuzzer"
|
||||
COV_BIN="../_cov_build/bootstrap_fuzzer"
|
||||
HARNESS_BIN="../_afl_build/bootstrap_fuzz_test"
|
||||
COV_BIN="../_cov_build/bootstrap_fuzz_test"
|
||||
# move to repo root
|
||||
cd ../
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
|
||||
load("@rules_fuzzing//fuzzing/private:binary.bzl", "fuzzing_binary") # buildifier: disable=bzl-visibility
|
||||
|
||||
cc_library(
|
||||
name = "fuzz_support",
|
||||
@ -27,9 +26,9 @@ cc_library(
|
||||
cc_fuzz_test(
|
||||
name = "bootstrap_fuzz_test",
|
||||
size = "small",
|
||||
srcs = ["bootstrap_harness.cc"],
|
||||
srcs = ["bootstrap_fuzz_test.cc"],
|
||||
copts = ["-UNDEBUG"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:bootstrap_fuzzer"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:bootstrap_fuzz_test"],
|
||||
deps = [
|
||||
":fuzz_support",
|
||||
":fuzz_tox",
|
||||
@ -58,9 +57,9 @@ cc_fuzz_test(
|
||||
cc_fuzz_test(
|
||||
name = "toxsave_fuzz_test",
|
||||
size = "small",
|
||||
srcs = ["toxsave_harness.cc"],
|
||||
srcs = ["toxsave_fuzz_test.cc"],
|
||||
copts = ["-UNDEBUG"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:toxsave_fuzzer"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:toxsave_fuzz_test"],
|
||||
deps = [
|
||||
":fuzz_support",
|
||||
"//c-toxcore/toxcore:tox",
|
||||
@ -80,12 +79,34 @@ cc_binary(
|
||||
],
|
||||
)
|
||||
|
||||
fuzzing_binary(
|
||||
name = "protodump_bin",
|
||||
testonly = True,
|
||||
binary = ":protodump",
|
||||
engine = "@rules_fuzzing//fuzzing:cc_engine",
|
||||
genrule(
|
||||
name = "e2e_fuzz_test_init",
|
||||
outs = [
|
||||
"e2e_fuzz_test_init.dat",
|
||||
"e2e_fuzz_test_bootstrap.dat",
|
||||
],
|
||||
cmd = "$(location :protodump) $(location e2e_fuzz_test_init.dat) $(location e2e_fuzz_test_bootstrap.dat)",
|
||||
tags = ["manual"],
|
||||
tools = [":protodump"],
|
||||
)
|
||||
|
||||
# bazel test --config=asan-libfuzzer //c-toxcore/testing/fuzzing:protodump_reduce_test
|
||||
cc_test(
|
||||
name = "protodump_reduce_test",
|
||||
size = "small",
|
||||
srcs = ["protodump_reduce.cc"],
|
||||
args = ["$(location :e2e_fuzz_test_init.dat)"],
|
||||
copts = ["-UNDEBUG"],
|
||||
data = [":e2e_fuzz_test_init.dat"],
|
||||
tags = ["manual"],
|
||||
deps = [
|
||||
":fuzz_support",
|
||||
":fuzz_tox",
|
||||
"//c-toxcore/toxcore:tox",
|
||||
"//c-toxcore/toxcore:tox_dispatch",
|
||||
"//c-toxcore/toxcore:tox_events",
|
||||
"@rules_fuzzing//fuzzing:cc_engine",
|
||||
],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
|
@ -9,22 +9,18 @@ else()
|
||||
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}/*")
|
||||
set(CORPUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/toktok-fuzzer/corpus/${target}_fuzz_test)
|
||||
file(GLOB CORPUS "${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})
|
||||
target_link_libraries(${target}_fuzz_test PRIVATE fuzz_support test_util toxcore_fuzz ${LIBFUZZER_LINKER_FLAGS})
|
||||
if(CORPUS)
|
||||
add_test(NAME ${target}_fuzz COMMAND ${CROSSCOMPILING_EMULATOR} ${target}_fuzz_test -max_total_time=10 ${CORPUS})
|
||||
set_property(TEST ${target}_fuzz PROPERTY ENVIRONMENT "LLVM_PROFILE_FILE=${target}.profraw;srcdir=${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Fuzzes the toxsave API
|
||||
add_executable(toxsave_fuzzer toxsave_harness.cc)
|
||||
target_link_libraries(toxsave_fuzzer PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
|
||||
|
||||
# Fuzzes the bootstrap process
|
||||
add_executable(bootstrap_fuzzer bootstrap_harness.cc)
|
||||
target_link_libraries(bootstrap_fuzzer PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
|
||||
fuzz_test(bootstrap .) # Fuzzes the bootstrap process
|
||||
fuzz_test(toxsave .) # Fuzzes the bootstrap process
|
||||
|
||||
fuzz_test(DHT ../../toxcore)
|
||||
fuzz_test(forwarding ../../toxcore)
|
||||
|
@ -83,9 +83,12 @@ void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
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);
|
||||
if (!(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
|
||||
|| err == TOX_ERR_FRIEND_ADD_MALLOC)) {
|
||||
printf("unexpected error: %s\n", tox_err_friend_add_to_string(err));
|
||||
}
|
||||
});
|
||||
tox_events_callback_friend_status(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) {
|
||||
@ -120,7 +123,7 @@ void TestBootstrap(Fuzz_Data &input)
|
||||
[](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
|
||||
const char *message, void *user_data) {
|
||||
// Log to stdout.
|
||||
if (DEBUG) {
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
|
||||
func, message);
|
||||
}
|
||||
@ -167,7 +170,7 @@ void TestBootstrap(Fuzz_Data &input)
|
||||
assert(dispatch != nullptr);
|
||||
setup_callbacks(dispatch);
|
||||
|
||||
while (input.size > 0) {
|
||||
while (!input.empty()) {
|
||||
Tox_Err_Events_Iterate error_iterate;
|
||||
Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
|
||||
assert(tox_events_equal(null_sys.sys.get(), events, events));
|
@ -110,9 +110,6 @@ void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
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) {
|
||||
@ -147,7 +144,7 @@ void TestEndToEnd(Fuzz_Data &input)
|
||||
[](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
|
||||
const char *message, void *user_data) {
|
||||
// Log to stdout.
|
||||
if (DEBUG) {
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
|
||||
func, message);
|
||||
}
|
||||
@ -170,7 +167,7 @@ void TestEndToEnd(Fuzz_Data &input)
|
||||
assert(dispatch != nullptr);
|
||||
setup_callbacks(dispatch);
|
||||
|
||||
while (input.size > 0) {
|
||||
while (!input.empty()) {
|
||||
Tox_Err_Events_Iterate error_iterate;
|
||||
Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
|
||||
assert(tox_events_equal(null_sys.sys.get(), events, events));
|
||||
|
@ -20,10 +20,6 @@
|
||||
#include "../../toxcore/tox_private.h"
|
||||
#include "func_conversion.h"
|
||||
|
||||
const bool DEBUG = false;
|
||||
|
||||
static constexpr tox_mono_time_cb *get_self_clock =  { return self->clock; };
|
||||
|
||||
// TODO(iphydf): Put this somewhere shared.
|
||||
struct Network_Addr {
|
||||
struct sockaddr_storage addr;
|
||||
@ -44,58 +40,67 @@ System::~System() { }
|
||||
|
||||
static int recv_common(Fuzz_Data &input, uint8_t *buf, size_t buf_len)
|
||||
{
|
||||
if (input.size < 2) {
|
||||
if (input.size() < 2) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const size_t fuzz_len = (input.data[0] << 8) | input.data[1];
|
||||
input.data += 2;
|
||||
input.size -= 2;
|
||||
CONSUME_OR_ABORT(const uint8_t *fuzz_len_bytes, input, 2);
|
||||
const std::size_t fuzz_len = (fuzz_len_bytes[0] << 8) | fuzz_len_bytes[1];
|
||||
|
||||
if (fuzz_len == 0xffff) {
|
||||
errno = EWOULDBLOCK;
|
||||
if (DEBUG) {
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf("recvfrom: no data for tox1\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf(
|
||||
"recvfrom: %zu (%02x, %02x) for tox1\n", fuzz_len, input.data[-2], input.data[-1]);
|
||||
"recvfrom: %zu (%02x, %02x) for tox1\n", fuzz_len, input.data()[-2], input.data()[-1]);
|
||||
}
|
||||
const size_t res = std::min(buf_len, std::min(fuzz_len, input.size));
|
||||
const size_t res = std::min(buf_len, std::min(fuzz_len, input.size()));
|
||||
|
||||
std::copy(input.data, input.data + res, buf);
|
||||
input.data += res;
|
||||
input.size -= res;
|
||||
CONSUME_OR_ABORT(const uint8_t *data, input, res);
|
||||
std::copy(data, data + res, buf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
static void *alloc_common(Fuzz_Data &data, F func)
|
||||
static void *report_alloc(const char *name, const char *func, std::size_t size, void *ptr)
|
||||
{
|
||||
CONSUME1_OR_RETURN_VAL(const uint8_t, want_alloc, data, func());
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
printf("%s: %s(%zu): %s\n", name, func, size, ptr == nullptr ? "false" : "true");
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename F, F Func, typename... Args>
|
||||
static void *alloc_common(const char *func, std::size_t size, Fuzz_Data &data, Args... args)
|
||||
{
|
||||
CONSUME1_OR_RETURN_VAL(
|
||||
const bool, want_alloc, data, report_alloc("tox1", func, size, Func(args...)));
|
||||
if (!want_alloc) {
|
||||
return nullptr;
|
||||
}
|
||||
return func();
|
||||
return report_alloc("tox1", func, size, Func(args...));
|
||||
}
|
||||
|
||||
static constexpr Memory_Funcs fuzz_memory_funcs = {
|
||||
/* .malloc = */
|
||||
 {
|
||||
return alloc_common(self->data, [=]() { return std::malloc(size); });
|
||||
return alloc_common<decltype(std::malloc), std::malloc>("malloc", size, self->data, size);
|
||||
},
|
||||
/* .calloc = */
|
||||
 {
|
||||
return alloc_common(self->data, [=]() { return std::calloc(nmemb, size); });
|
||||
return alloc_common<decltype(std::calloc), std::calloc>(
|
||||
"calloc", nmemb * size, self->data, nmemb, size);
|
||||
},
|
||||
/* .realloc = */
|
||||
 {
|
||||
return alloc_common(self->data, [=]() { return std::realloc(ptr, size); });
|
||||
return alloc_common<decltype(std::realloc), std::realloc>(
|
||||
"realloc", size, self->data, ptr, size);
|
||||
},
|
||||
/* .free = */
|
||||
 { std::free(ptr); },
|
||||
@ -110,7 +115,7 @@ static constexpr Network_Funcs fuzz_network_funcs = {
|
||||
 {
|
||||
assert(sock == 42 || sock == 1337);
|
||||
const size_t count = random_u16(self->rng.get());
|
||||
return static_cast<int>(std::min(count, self->data.size));
|
||||
return static_cast<int>(std::min(count, self->data.size()));
|
||||
},
|
||||
/* .recv = */
|
||||
 {
|
||||
@ -163,14 +168,17 @@ static constexpr Random_Funcs fuzz_random_funcs = {
|
||||
/* .random_bytes = */
|
||||
 {
|
||||
// Amount of data is limited
|
||||
const size_t bytes_read = std::min(length, self->data.size);
|
||||
const size_t bytes_read = std::min(length, self->data.size());
|
||||
// Initialize everything to make MSAN and others happy
|
||||
std::memset(bytes, 0, length);
|
||||
std::copy(self->data.data, self->data.data + bytes_read, bytes);
|
||||
self->data.data += bytes_read;
|
||||
self->data.size -= bytes_read;
|
||||
if (DEBUG) {
|
||||
std::printf("rng: %02x..%02x[%zu] -> tox1\n", bytes[0], bytes[length - 1], length);
|
||||
CONSUME_OR_ABORT(const uint8_t *data, self->data, bytes_read);
|
||||
std::copy(data, data + bytes_read, bytes);
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
if (length == 1) {
|
||||
std::printf("rng: %d (0x%02x)\n", bytes[0], bytes[0]);
|
||||
} else {
|
||||
std::printf("rng: %02x..%02x[%zu]\n", bytes[0], bytes[length - 1], length);
|
||||
}
|
||||
}
|
||||
},
|
||||
/* .random_uniform = */
|
||||
@ -194,7 +202,7 @@ Fuzz_System::Fuzz_System(Fuzz_Data &input)
|
||||
}
|
||||
, data(input)
|
||||
{
|
||||
sys->mono_time_callback = get_self_clock;
|
||||
sys->mono_time_callback = [](void *self) { return static_cast<Fuzz_System *>(self)->clock; };
|
||||
sys->mono_time_user_data = this;
|
||||
sys->mem = mem.get();
|
||||
sys->ns = ns.get();
|
||||
@ -281,7 +289,7 @@ Null_System::Null_System()
|
||||
std::make_unique<Random>(Random{&null_random_funcs, this}),
|
||||
}
|
||||
{
|
||||
sys->mono_time_callback = get_self_clock;
|
||||
sys->mono_time_callback = [](void *self) { return static_cast<Null_System *>(self)->clock; };
|
||||
sys->mono_time_user_data = this;
|
||||
sys->mem = mem.get();
|
||||
sys->ns = ns.get();
|
||||
@ -298,7 +306,25 @@ static uint16_t get_port(const Network_Addr *addr)
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr Memory_Funcs record_memory_funcs = null_memory_funcs;
|
||||
static constexpr Memory_Funcs record_memory_funcs = {
|
||||
/* .malloc = */
|
||||
 {
|
||||
self->push(true);
|
||||
return report_alloc(self->name_, "malloc", size, std::malloc(size));
|
||||
},
|
||||
/* .calloc = */
|
||||
 {
|
||||
self->push(true);
|
||||
return report_alloc(self->name_, "calloc", nmemb * size, std::calloc(nmemb, size));
|
||||
},
|
||||
/* .realloc = */
|
||||
 {
|
||||
self->push(true);
|
||||
return report_alloc(self->name_, "realloc", size, std::realloc(ptr, size));
|
||||
},
|
||||
/* .free = */
|
||||
 { std::free(ptr); },
|
||||
};
|
||||
|
||||
static constexpr Network_Funcs record_network_funcs = {
|
||||
/* .close = */  { return 0; },
|
||||
@ -326,11 +352,10 @@ static constexpr Network_Funcs record_network_funcs = {
|
||||
 {
|
||||
assert(sock == 42);
|
||||
if (self->recvq.empty()) {
|
||||
self->recording.push_back(0xff);
|
||||
self->recording.push_back(0xff);
|
||||
self->push("\xff\xff");
|
||||
errno = EWOULDBLOCK;
|
||||
if (DEBUG) {
|
||||
std::printf("recvfrom: no data for %s\n", self->name_);
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf("%s: recvfrom: no data\n", self->name_);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -350,13 +375,13 @@ static constexpr Network_Funcs record_network_funcs = {
|
||||
addr->size = sizeof(struct sockaddr);
|
||||
|
||||
assert(recvlen > 0 && recvlen <= INT_MAX);
|
||||
self->recording.push_back(recvlen >> 8);
|
||||
self->recording.push_back(recvlen & 0xff);
|
||||
if (DEBUG) {
|
||||
std::printf("recvfrom: %zu (%02x, %02x) for %s\n", recvlen, self->recording.end()[-2],
|
||||
self->recording.end()[-1], self->name_);
|
||||
self->push(uint8_t(recvlen >> 8));
|
||||
self->push(uint8_t(recvlen & 0xff));
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf("%s: recvfrom: %zu (%02x, %02x)\n", self->name_, recvlen,
|
||||
self->recording().end()[-2], self->recording().end()[-1]);
|
||||
}
|
||||
self->recording.insert(self->recording.end(), buf, buf + recvlen);
|
||||
self->push(buf, recvlen);
|
||||
return static_cast<int>(recvlen);
|
||||
},
|
||||
/* .send = */
|
||||
@ -390,11 +415,11 @@ static constexpr Random_Funcs record_random_funcs = {
|
||||
 {
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
bytes[i] = simple_rng(self->seed_) & 0xff;
|
||||
self->recording.push_back(bytes[i]);
|
||||
self->push(bytes[i]);
|
||||
}
|
||||
if (DEBUG) {
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf(
|
||||
"rng: %02x..%02x[%zu] -> %s\n", bytes[0], bytes[length - 1], length, self->name_);
|
||||
"%s: rng: %02x..%02x[%zu]\n", self->name_, bytes[0], bytes[length - 1], length);
|
||||
}
|
||||
},
|
||||
/* .random_uniform = */
|
||||
@ -412,7 +437,7 @@ Record_System::Record_System(Global &global, uint64_t seed, const char *name)
|
||||
, seed_(seed)
|
||||
, name_(name)
|
||||
{
|
||||
sys->mono_time_callback = get_self_clock;
|
||||
sys->mono_time_callback = [](void *self) { return static_cast<Record_System *>(self)->clock; };
|
||||
sys->mono_time_user_data = this;
|
||||
sys->mem = mem.get();
|
||||
sys->ns = ns.get();
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
@ -17,12 +18,19 @@
|
||||
#include "../../toxcore/tox.h"
|
||||
|
||||
struct Fuzz_Data {
|
||||
const uint8_t *data;
|
||||
std::size_t size;
|
||||
static constexpr bool DEBUG = false;
|
||||
static constexpr std::size_t TRACE_TRAP = -1; // 579;
|
||||
|
||||
private:
|
||||
const uint8_t *data_;
|
||||
const uint8_t *base_;
|
||||
std::size_t size_;
|
||||
|
||||
public:
|
||||
Fuzz_Data(const uint8_t *input_data, std::size_t input_size)
|
||||
: data(input_data)
|
||||
, size(input_size)
|
||||
: data_(input_data)
|
||||
, base_(input_data)
|
||||
, size_(input_size)
|
||||
{
|
||||
}
|
||||
|
||||
@ -30,25 +38,54 @@ struct Fuzz_Data {
|
||||
Fuzz_Data(const Fuzz_Data &rhs) = delete;
|
||||
|
||||
struct Consumer {
|
||||
const char *func;
|
||||
Fuzz_Data &fd;
|
||||
|
||||
operator bool()
|
||||
{
|
||||
// Special case because memcpy causes UB for bool (which can't be
|
||||
// anything other than 0 or 1).
|
||||
const bool val = fd.data_[0];
|
||||
if (DEBUG) {
|
||||
std::printf("consume@%zu(%s): bool %s\n", fd.pos(), func, val ? "true" : "false");
|
||||
}
|
||||
++fd.data_;
|
||||
--fd.size_;
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
operator T()
|
||||
{
|
||||
const uint8_t *bytes = fd.consume(sizeof(T));
|
||||
const uint8_t *bytes = fd.consume(func, sizeof(T));
|
||||
T val;
|
||||
std::memcpy(&val, bytes, sizeof(T));
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
Consumer consume1() { return Consumer{*this}; }
|
||||
Consumer consume1(const char *func) { return Consumer{func, *this}; }
|
||||
std::size_t size() const { return size_; }
|
||||
std::size_t pos() const { return data_ - base_; }
|
||||
const uint8_t *data() const { return data_; }
|
||||
bool empty() const { return size_ == 0; }
|
||||
|
||||
const uint8_t *consume(std::size_t count)
|
||||
const uint8_t *consume(const char *func, std::size_t count)
|
||||
{
|
||||
const uint8_t *val = data;
|
||||
data += count;
|
||||
size -= count;
|
||||
const uint8_t *val = data_;
|
||||
if (DEBUG) {
|
||||
if (pos() == TRACE_TRAP) {
|
||||
__asm__("int $3");
|
||||
}
|
||||
if (count == 1) {
|
||||
std::printf("consume@%zu(%s): %d (0x%02x)\n", pos(), func, val[0], val[0]);
|
||||
} else if (count != 0) {
|
||||
std::printf("consume@%zu(%s): %02x..%02x[%zu]\n", pos(), func, val[0],
|
||||
val[count - 1], count);
|
||||
}
|
||||
}
|
||||
data_ += count;
|
||||
size_ -= count;
|
||||
return val;
|
||||
}
|
||||
};
|
||||
@ -64,10 +101,10 @@ struct Fuzz_Data {
|
||||
* @endcode
|
||||
*/
|
||||
#define CONSUME1_OR_RETURN(TYPE, NAME, INPUT) \
|
||||
if (INPUT.size < sizeof(TYPE)) { \
|
||||
if (INPUT.size() < sizeof(TYPE)) { \
|
||||
return; \
|
||||
} \
|
||||
TYPE NAME = INPUT.consume1()
|
||||
TYPE NAME = INPUT.consume1(__func__)
|
||||
|
||||
/** @brief Consumes 1 byte of the fuzzer input or returns a value if no data
|
||||
* available.
|
||||
@ -81,10 +118,10 @@ struct Fuzz_Data {
|
||||
* @endcode
|
||||
*/
|
||||
#define CONSUME1_OR_RETURN_VAL(TYPE, NAME, INPUT, VAL) \
|
||||
if (INPUT.size < sizeof(TYPE)) { \
|
||||
if (INPUT.size() < sizeof(TYPE)) { \
|
||||
return VAL; \
|
||||
} \
|
||||
TYPE NAME = INPUT.consume1()
|
||||
TYPE NAME = INPUT.consume1(__func__)
|
||||
|
||||
/** @brief Consumes SIZE bytes of the fuzzer input or returns if not enough data available.
|
||||
*
|
||||
@ -98,39 +135,55 @@ struct Fuzz_Data {
|
||||
* @endcode
|
||||
*/
|
||||
#define CONSUME_OR_RETURN(DECL, INPUT, SIZE) \
|
||||
if (INPUT.size < SIZE) { \
|
||||
if (INPUT.size() < SIZE) { \
|
||||
return; \
|
||||
} \
|
||||
DECL = INPUT.consume(SIZE)
|
||||
DECL = INPUT.consume(__func__, SIZE)
|
||||
|
||||
#define CONSUME_OR_RETURN_VAL(DECL, INPUT, SIZE, VAL) \
|
||||
if (INPUT.size < SIZE) { \
|
||||
if (INPUT.size() < SIZE) { \
|
||||
return VAL; \
|
||||
} \
|
||||
DECL = INPUT.consume(SIZE)
|
||||
DECL = INPUT.consume(__func__, 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.
|
||||
}
|
||||
#define CONSUME_OR_ABORT(DECL, INPUT, SIZE) \
|
||||
if (INPUT.size() < SIZE) { \
|
||||
abort(); \
|
||||
} \
|
||||
DECL = INPUT.consume(__func__, SIZE)
|
||||
|
||||
template <typename Arg, typename... Args>
|
||||
void fuzz_select_target(uint8_t selector, Fuzz_Data &input, Arg &&fn, Args &&...args)
|
||||
{
|
||||
if (selector == sizeof...(Args)) {
|
||||
return fn(input);
|
||||
using Fuzz_Target = void (*)(Fuzz_Data &input);
|
||||
|
||||
template <Fuzz_Target... Args>
|
||||
struct Fuzz_Target_Selector;
|
||||
|
||||
template <Fuzz_Target Arg, Fuzz_Target... Args>
|
||||
struct Fuzz_Target_Selector<Arg, Args...> {
|
||||
static void select(uint8_t selector, Fuzz_Data &input)
|
||||
{
|
||||
if (selector == sizeof...(Args)) {
|
||||
return Arg(input);
|
||||
}
|
||||
return Fuzz_Target_Selector<Args...>::select(selector, input);
|
||||
}
|
||||
return fuzz_select_target(selector - 1, input, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
void fuzz_select_target(const uint8_t *data, std::size_t size, Args &&...args)
|
||||
template <>
|
||||
struct Fuzz_Target_Selector<> {
|
||||
static void select(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 <Fuzz_Target... Args>
|
||||
void fuzz_select_target(const uint8_t *data, std::size_t size)
|
||||
{
|
||||
Fuzz_Data input{data, size};
|
||||
|
||||
CONSUME1_OR_RETURN(const uint8_t, selector, input);
|
||||
return fuzz_select_target(selector, input, std::forward<Args>(args)...);
|
||||
return Fuzz_Target_Selector<Args...>::select(selector, input);
|
||||
}
|
||||
|
||||
struct Memory;
|
||||
@ -138,6 +191,18 @@ struct Network;
|
||||
struct Random;
|
||||
|
||||
struct System {
|
||||
/** @brief Deterministic system clock for this instance.
|
||||
*
|
||||
* Different instances can evolve independently. The time is initialised
|
||||
* with a large number, because otherwise many zero-initialised "empty"
|
||||
* friends inside toxcore will be "not timed out" for a long time, messing
|
||||
* up some logic. Tox moderately depends on the clock being fairly high up
|
||||
* (not close to 0).
|
||||
*
|
||||
* We make it a nice large round number so we can recognise it when debugging.
|
||||
*/
|
||||
uint64_t clock = 1000000000;
|
||||
|
||||
std::unique_ptr<Tox_System> sys;
|
||||
std::unique_ptr<Memory> mem;
|
||||
std::unique_ptr<Network> ns;
|
||||
@ -150,16 +215,6 @@ struct System {
|
||||
// Not inline because sizeof of the above 2 structs is not known everywhere.
|
||||
~System();
|
||||
|
||||
/** @brief Deterministic system clock for this instance.
|
||||
*
|
||||
* Different instances can evolve independently. The time is initialised
|
||||
* with a large number, because otherwise many zero-initialised "empty"
|
||||
* friends inside toxcore will be "not timed out" for a long time, messing
|
||||
* up some logic. Tox moderately depends on the clock being fairly high up
|
||||
* (not close to 0).
|
||||
*/
|
||||
uint64_t clock = UINT32_MAX;
|
||||
|
||||
/**
|
||||
* During bootstrap, move the time forward a decent amount, because friend
|
||||
* finding and bootstrapping takes significant (around 10 seconds) wall
|
||||
@ -210,6 +265,8 @@ struct Null_System : System {
|
||||
* initialised with the same seed will be identical (same keys, etc.).
|
||||
*/
|
||||
struct Record_System : System {
|
||||
static constexpr bool DEBUG = Fuzz_Data::DEBUG;
|
||||
|
||||
/** @brief State shared between all tox instances. */
|
||||
struct Global {
|
||||
/** @brief Bound UDP ports and their system instance.
|
||||
@ -231,13 +288,60 @@ struct Record_System : System {
|
||||
|
||||
std::deque<std::pair<uint16_t, std::vector<uint8_t>>> recvq;
|
||||
uint16_t port = 0; //!< Sending port for this system instance.
|
||||
std::vector<uint8_t> recording;
|
||||
|
||||
explicit Record_System(Global &global, uint64_t seed, const char *name);
|
||||
Record_System(Global &global, uint64_t seed, const char *name);
|
||||
Record_System(const Record_System &) = delete;
|
||||
Record_System operator=(const Record_System &) = delete;
|
||||
|
||||
/** @brief Deposit a network packet in this instance's recvq.
|
||||
*/
|
||||
void receive(uint16_t send_port, const uint8_t *buf, size_t len);
|
||||
|
||||
void push(bool byte)
|
||||
{
|
||||
if (DEBUG) {
|
||||
if (recording_.size() == Fuzz_Data::TRACE_TRAP) {
|
||||
__asm__("int $3");
|
||||
}
|
||||
std::printf("%s: produce@%zu(bool %s)\n", name_, recording_.size(), byte ? "true" : "false");
|
||||
}
|
||||
recording_.push_back(byte);
|
||||
}
|
||||
|
||||
void push(uint8_t byte)
|
||||
{
|
||||
if (DEBUG) {
|
||||
if (recording_.size() == Fuzz_Data::TRACE_TRAP) {
|
||||
__asm__("int $3");
|
||||
}
|
||||
std::printf("%s: produce@%zu(%u (0x%02x))\n", name_, recording_.size(), byte, byte);
|
||||
}
|
||||
recording_.push_back(byte);
|
||||
}
|
||||
|
||||
void push(const uint8_t *bytes, std::size_t size)
|
||||
{
|
||||
if (DEBUG) {
|
||||
if (recording_.size() == Fuzz_Data::TRACE_TRAP) {
|
||||
__asm__("int $3");
|
||||
}
|
||||
std::printf("%s: produce@%zu(%02x..%02x[%zu])\n", name_, recording_.size(), bytes[0],
|
||||
bytes[size - 1], size);
|
||||
}
|
||||
recording_.insert(recording_.end(), bytes, bytes + size);
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
void push(const char (&bytes)[N])
|
||||
{
|
||||
push(reinterpret_cast<const uint8_t *>(bytes), N - 1);
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> &recording() const { return recording_; }
|
||||
std::vector<uint8_t> take_recording() const { return std::move(recording_); }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> recording_;
|
||||
};
|
||||
|
||||
/** @brief Enable debug logging.
|
||||
|
@ -17,8 +17,8 @@
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* bazel build //c-toxcore/testing/fuzzing:protodump_bin && \
|
||||
* bazel-bin/c-toxcore/testing/fuzzing/protodump_bin
|
||||
* bazel build //c-toxcore/testing/fuzzing:protodump && \
|
||||
* bazel-bin/c-toxcore/testing/fuzzing/protodump
|
||||
*/
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
@ -165,15 +165,14 @@ void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
});
|
||||
}
|
||||
|
||||
void dump(std::vector<uint8_t> &recording, const char *filename)
|
||||
void dump(std::vector<uint8_t> recording, const char *filename)
|
||||
{
|
||||
std::printf("%zu bytes: %s\n", recording.size(), filename);
|
||||
std::ofstream(filename, std::ios::binary)
|
||||
.write(reinterpret_cast<const char *>(recording.data()), recording.size());
|
||||
recording.clear();
|
||||
}
|
||||
|
||||
void RecordBootstrap()
|
||||
void RecordBootstrap(const char *init, const char *bootstrap)
|
||||
{
|
||||
Record_System::Global global;
|
||||
|
||||
@ -258,13 +257,17 @@ void RecordBootstrap()
|
||||
sys1.clock += clock_increment;
|
||||
sys2.clock += clock_increment;
|
||||
|
||||
sys1.recording.push_back(clock_increment);
|
||||
sys2.recording.push_back(clock_increment);
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
printf("tox1: rng: %d (for clock)\n", clock_increment);
|
||||
printf("tox2: rng: %d (for clock)\n", clock_increment);
|
||||
}
|
||||
sys1.push(clock_increment);
|
||||
sys2.push(clock_increment);
|
||||
};
|
||||
|
||||
while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE
|
||||
|| tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE) {
|
||||
if (DEBUG) {
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf("tox1: %d, tox2: %d\n", tox_self_get_connection_status(tox1),
|
||||
tox_self_get_connection_status(tox2));
|
||||
}
|
||||
@ -279,7 +282,7 @@ void RecordBootstrap()
|
||||
|
||||
while (tox_friend_get_connection_status(tox2, friend_number, nullptr) == TOX_CONNECTION_NONE
|
||||
|| tox_friend_get_connection_status(tox1, 0, nullptr) == TOX_CONNECTION_NONE) {
|
||||
if (DEBUG) {
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf("tox1: %d, tox2: %d, tox1 -> tox2: %d, tox2 -> tox1: %d\n",
|
||||
tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2),
|
||||
tox_friend_get_connection_status(tox1, 0, nullptr),
|
||||
@ -290,10 +293,10 @@ void RecordBootstrap()
|
||||
|
||||
std::printf("tox clients connected\n");
|
||||
|
||||
dump(sys1.recording, "tools/toktok-fuzzer/init/e2e_fuzz_test.dat");
|
||||
dump(sys1.take_recording(), init);
|
||||
|
||||
while (done1 < MESSAGE_COUNT && done2 < MESSAGE_COUNT) {
|
||||
if (DEBUG) {
|
||||
if (Fuzz_Data::DEBUG) {
|
||||
std::printf("tox1: %d, tox2: %d, tox1 -> tox2: %d, tox2 -> tox1: %d\n",
|
||||
tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2),
|
||||
tox_friend_get_connection_status(tox1, 0, nullptr),
|
||||
@ -308,9 +311,18 @@ void RecordBootstrap()
|
||||
tox_kill(tox2);
|
||||
tox_kill(tox1);
|
||||
|
||||
dump(sys1.recording, "tools/toktok-fuzzer/corpus/e2e_fuzz_test/bootstrap.dat");
|
||||
dump(sys1.recording(), bootstrap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(void) { RecordBootstrap(); }
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *init = "tools/toktok-fuzzer/init/e2e_fuzz_test.dat";
|
||||
const char *bootstrap = "tools/toktok-fuzzer/corpus/e2e_fuzz_test/bootstrap.dat";
|
||||
if (argc == 3) {
|
||||
init = argv[1];
|
||||
bootstrap = argv[2];
|
||||
}
|
||||
RecordBootstrap(init, bootstrap);
|
||||
}
|
||||
|
@ -11,14 +11,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Whether to abort the program if a friend connection can be established.
|
||||
*
|
||||
* This is useful to make the fuzzer produce minimal startup data so the
|
||||
* interesting part of the fuzzer (the part that comes after the friend
|
||||
* connection is established) can run sooner and thus more frequently.
|
||||
*/
|
||||
constexpr bool REDUCE_PROTODUMP = false;
|
||||
constexpr bool PROTODUMP_DEBUG = Fuzz_Data::DEBUG;
|
||||
|
||||
void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
{
|
||||
@ -32,10 +25,7 @@ void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
});
|
||||
tox_events_callback_conference_invite(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Conference_Invite *event, void *user_data) {
|
||||
const uint32_t friend_number = tox_event_conference_invite_get_friend_number(event);
|
||||
const uint8_t *cookie = tox_event_conference_invite_get_cookie(event);
|
||||
const uint32_t cookie_length = tox_event_conference_invite_get_cookie_length(event);
|
||||
tox_conference_join(tox, friend_number, cookie, cookie_length, nullptr);
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_conference_message(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Conference_Message *event, void *user_data) {
|
||||
@ -59,9 +49,7 @@ void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
});
|
||||
tox_events_callback_file_recv(
|
||||
dispatch, [](Tox *tox, const Tox_Event_File_Recv *event, void *user_data) {
|
||||
const uint32_t friend_number = tox_event_file_recv_get_friend_number(event);
|
||||
const uint32_t file_number = tox_event_file_recv_get_file_number(event);
|
||||
tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_file_recv_chunk(
|
||||
dispatch, [](Tox *tox, const Tox_Event_File_Recv_Chunk *event, void *user_data) {
|
||||
@ -76,58 +64,65 @@ void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
// OK: friend came online.
|
||||
const uint32_t friend_number
|
||||
= tox_event_friend_connection_status_get_friend_number(event);
|
||||
assert(friend_number != UINT32_MAX);
|
||||
assert(friend_number == 0);
|
||||
const uint8_t message = 'A';
|
||||
Tox_Err_Friend_Send_Message err;
|
||||
tox_friend_send_message(tox, friend_number, TOX_MESSAGE_TYPE_NORMAL, &message, 1, &err);
|
||||
assert(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK);
|
||||
});
|
||||
tox_events_callback_friend_lossless_packet(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Lossless_Packet *event, void *user_data) {
|
||||
const uint32_t friend_number
|
||||
= tox_event_friend_lossless_packet_get_friend_number(event);
|
||||
const uint32_t data_length = tox_event_friend_lossless_packet_get_data_length(event);
|
||||
const uint8_t *data = tox_event_friend_lossless_packet_get_data(event);
|
||||
tox_friend_send_lossless_packet(tox, friend_number, data, data_length, nullptr);
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_lossy_packet(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Lossy_Packet *event, void *user_data) {
|
||||
const uint32_t friend_number = tox_event_friend_lossy_packet_get_friend_number(event);
|
||||
const uint32_t data_length = tox_event_friend_lossy_packet_get_data_length(event);
|
||||
const uint8_t *data = tox_event_friend_lossy_packet_get_data(event);
|
||||
tox_friend_send_lossy_packet(tox, friend_number, data, data_length, nullptr);
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_message(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Message *event, void *user_data) {
|
||||
const uint32_t friend_number = tox_event_friend_message_get_friend_number(event);
|
||||
const Tox_Message_Type type = tox_event_friend_message_get_type(event);
|
||||
assert(friend_number == 0);
|
||||
const uint32_t message_length = tox_event_friend_message_get_message_length(event);
|
||||
assert(message_length == 1);
|
||||
const uint8_t *message = tox_event_friend_message_get_message(event);
|
||||
tox_friend_send_message(tox, friend_number, type, message, message_length, nullptr);
|
||||
const uint8_t reply = message[0] + 1;
|
||||
Tox_Err_Friend_Send_Message err;
|
||||
tox_friend_send_message(tox, friend_number, TOX_MESSAGE_TYPE_NORMAL, &reply, 1, &err);
|
||||
assert(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK);
|
||||
});
|
||||
tox_events_callback_friend_name(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Name *event, void *user_data) {
|
||||
// OK: friend name received.
|
||||
const uint32_t friend_number = tox_event_friend_name_get_friend_number(event);
|
||||
assert(friend_number == 0);
|
||||
});
|
||||
tox_events_callback_friend_read_receipt(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Read_Receipt *event, void *user_data) {
|
||||
// OK: message has been received.
|
||||
const uint32_t friend_number = tox_event_friend_read_receipt_get_friend_number(event);
|
||||
assert(friend_number == 0);
|
||||
const uint32_t message_id = tox_event_friend_read_receipt_get_message_id(event);
|
||||
uint32_t *done = static_cast<uint32_t *>(user_data);
|
||||
*done = std::max(*done, message_id);
|
||||
});
|
||||
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) {
|
||||
// OK: friend status received.
|
||||
const uint32_t friend_number = tox_event_friend_status_get_friend_number(event);
|
||||
assert(friend_number == 0);
|
||||
});
|
||||
tox_events_callback_friend_status_message(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Status_Message *event, void *user_data) {
|
||||
// OK: friend status message received.
|
||||
const uint32_t friend_number = tox_event_friend_status_message_get_friend_number(event);
|
||||
assert(friend_number == 0);
|
||||
});
|
||||
tox_events_callback_friend_typing(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Typing *event, void *user_data) {
|
||||
// OK: friend may be typing.
|
||||
const uint32_t friend_number = tox_event_friend_typing_get_friend_number(event);
|
||||
assert(friend_number == 0);
|
||||
assert(!tox_event_friend_typing_get_typing(event));
|
||||
});
|
||||
tox_events_callback_self_connection_status(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Self_Connection_Status *event, void *user_data) {
|
||||
@ -137,6 +132,15 @@ void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
|
||||
void TestEndToEnd(Fuzz_Data &input)
|
||||
{
|
||||
/**
|
||||
* Whether to abort the program if a friend connection can be established.
|
||||
*
|
||||
* This is useful to make the fuzzer produce minimal startup data so the
|
||||
* interesting part of the fuzzer (the part that comes after the friend
|
||||
* connection is established) can run sooner and thus more frequently.
|
||||
*/
|
||||
const bool PROTODUMP_REDUCE = getenv("PROTODUMP_REDUCE") != nullptr;
|
||||
|
||||
Fuzz_System sys(input);
|
||||
|
||||
Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free);
|
||||
@ -148,7 +152,7 @@ void TestEndToEnd(Fuzz_Data &input)
|
||||
[](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
|
||||
const char *message, void *user_data) {
|
||||
// Log to stdout.
|
||||
if (DEBUG) {
|
||||
if (PROTODUMP_DEBUG) {
|
||||
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
|
||||
func, message);
|
||||
}
|
||||
@ -171,20 +175,26 @@ void TestEndToEnd(Fuzz_Data &input)
|
||||
assert(dispatch != nullptr);
|
||||
setup_callbacks(dispatch);
|
||||
|
||||
while (input.size > 0) {
|
||||
while (!input.empty()) {
|
||||
Tox_Err_Events_Iterate error_iterate;
|
||||
Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
|
||||
assert(tox_events_equal(tox_get_system(tox), events, events));
|
||||
tox_events_equal(tox_get_system(tox), events, events); // TODO(iphydf): assert?
|
||||
tox_dispatch_invoke(dispatch, events, tox, nullptr);
|
||||
tox_events_free(events);
|
||||
sys.clock += std::max(System::MIN_ITERATION_INTERVAL, random_u08(sys.rng.get()));
|
||||
const uint8_t clock_increment = random_u08(sys.rng.get());
|
||||
if (PROTODUMP_DEBUG) {
|
||||
printf("clock increment: %d\n", clock_increment);
|
||||
}
|
||||
sys.clock += std::max(System::MIN_ITERATION_INTERVAL, clock_increment);
|
||||
}
|
||||
|
||||
if (REDUCE_PROTODUMP) {
|
||||
if (PROTODUMP_REDUCE) {
|
||||
assert(tox_friend_get_connection_status(tox, 0, nullptr) != 2);
|
||||
} else {
|
||||
printf("friend: %d\n", tox_friend_get_connection_status(tox, 0, nullptr));
|
||||
printf("self: %d\n", tox_self_get_connection_status(tox));
|
||||
assert(tox_friend_get_connection_status(tox, 0, nullptr) == 2);
|
||||
assert(input.empty());
|
||||
}
|
||||
|
||||
tox_dispatch_free(dispatch);
|
||||
|
14
external/toxcore/c-toxcore/testing/fuzzing/rebuild_protodump
vendored
Executable file
14
external/toxcore/c-toxcore/testing/fuzzing/rebuild_protodump
vendored
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
bazel test --config=asan-libfuzzer //c-toxcore/testing/fuzzing:protodump_reduce_test
|
||||
|
||||
bazel build --config=asan-libfuzzer //c-toxcore/testing/fuzzing:protodump
|
||||
bazel-bin/c-toxcore/testing/fuzzing/protodump | grep -v '^tox2'
|
||||
|
||||
bazel build --config=asan-libfuzzer //c-toxcore/testing/fuzzing:protodump_reduce_bin
|
||||
bazel-bin/c-toxcore/testing/fuzzing/protodump_reduce_bin "$PWD/tools/toktok-fuzzer/init/e2e_fuzz_test.dat"
|
||||
|
||||
#export PROTODUMP_REDUCE=1
|
||||
#bazel-bin/c-toxcore/testing/fuzzing/protodump_reduce_bin -minimize_crash=1 "$PWD/tools/toktok-fuzzer/init/e2e_fuzz_test.dat"
|
@ -17,7 +17,7 @@ void TestSaveDataLoading(Fuzz_Data &input)
|
||||
assert(tox_options != nullptr);
|
||||
assert(error_options == TOX_ERR_OPTIONS_NEW_OK);
|
||||
|
||||
const size_t savedata_size = input.size;
|
||||
const size_t savedata_size = input.size();
|
||||
CONSUME_OR_RETURN(const uint8_t *savedata, input, savedata_size);
|
||||
|
||||
Null_System sys;
|
52
external/toxcore/c-toxcore/testing/run_afl.sh
vendored
52
external/toxcore/c-toxcore/testing/run_afl.sh
vendored
@ -5,7 +5,7 @@ COMMON_CMAKE_OPTIONS="-DCMAKE_C_COMPILER=afl-clang-lto -DCMAKE_CXX_COMPILER=afl-
|
||||
# move to repo root
|
||||
cd ../
|
||||
|
||||
# build fuzzer target UBSAN
|
||||
# build fuzz_test target UBSAN
|
||||
mkdir -p _afl_build_ubsan
|
||||
cd _afl_build_ubsan
|
||||
|
||||
@ -14,14 +14,14 @@ export AFL_USE_UBSAN=1
|
||||
# build c-toxcore using afl instrumentation
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
|
||||
|
||||
# build fuzzer target
|
||||
cmake --build ./ --target bootstrap_fuzzer
|
||||
# build fuzz_test target
|
||||
cmake --build ./ --target bootstrap_fuzz_test
|
||||
|
||||
unset AFL_USE_UBSAN
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer target MSAN
|
||||
# build fuzz_test target MSAN
|
||||
mkdir -p _afl_build_msan
|
||||
cd _afl_build_msan
|
||||
|
||||
@ -30,14 +30,14 @@ export AFL_USE_MSAN=1
|
||||
# build c-toxcore using afl instrumentation
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
|
||||
|
||||
# build fuzzer target
|
||||
cmake --build ./ --target bootstrap_fuzzer
|
||||
# build fuzz_test target
|
||||
cmake --build ./ --target bootstrap_fuzz_test
|
||||
|
||||
unset AFL_USE_MSAN
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer target ASAN
|
||||
# build fuzz_test target ASAN
|
||||
mkdir -p _afl_build_asan
|
||||
cd _afl_build_asan
|
||||
|
||||
@ -46,26 +46,26 @@ export AFL_USE_ASAN=1
|
||||
# build c-toxcore using afl instrumentation
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
|
||||
|
||||
# build fuzzer target
|
||||
cmake --build ./ --target bootstrap_fuzzer
|
||||
# build fuzz_test target
|
||||
cmake --build ./ --target bootstrap_fuzz_test
|
||||
|
||||
unset AFL_USE_ASAN
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer target without sanitizers for afl-tmin
|
||||
# build fuzz_test target without sanitizers for afl-tmin
|
||||
mkdir -p _afl_build
|
||||
cd _afl_build
|
||||
|
||||
# build c-toxcore using afl instrumentation
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
|
||||
|
||||
# build fuzzer target
|
||||
cmake --build ./ --target bootstrap_fuzzer
|
||||
# build fuzz_test target
|
||||
cmake --build ./ --target bootstrap_fuzz_test
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer target with CmpLog
|
||||
# build fuzz_test target with CmpLog
|
||||
mkdir -p _afl_build_cmplog
|
||||
cd _afl_build_cmplog
|
||||
|
||||
@ -74,27 +74,27 @@ export AFL_LLVM_CMPLOG=1
|
||||
# build c-toxcore using afl instrumentation
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
|
||||
|
||||
# build fuzzer target
|
||||
cmake --build ./ --target bootstrap_fuzzer
|
||||
# build fuzz_test target
|
||||
cmake --build ./ --target bootstrap_fuzz_test
|
||||
|
||||
unset AFL_LLVM_CMPLOG
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer target for code coverage
|
||||
# build fuzz_test target for code coverage
|
||||
mkdir -p _cov_build
|
||||
cd _cov_build
|
||||
|
||||
# build c-toxcore using afl instrumentation
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-fprofile-arcs -ftest-coverage" -DCMAKE_C_FLAGS="-fprofile-arcs -ftest-coverage" -DCMAKE_VERBOSE_MAKEFILE=ON "$COMMON_CMAKE_OPTIONS" ..
|
||||
|
||||
# build fuzzer target
|
||||
cmake --build ./ --target bootstrap_fuzzer
|
||||
# build fuzz_test target
|
||||
cmake --build ./ --target bootstrap_fuzz_test
|
||||
|
||||
# back to repo root
|
||||
cd ../
|
||||
|
||||
# Create fuzzer working directory
|
||||
# Create fuzz_test working directory
|
||||
|
||||
mkdir -p _afl_out
|
||||
|
||||
@ -106,21 +106,21 @@ export AFL_AUTORESUME=1
|
||||
# faster startup
|
||||
export AFL_FAST_CAL=1
|
||||
|
||||
echo "connect to the fuzzers using: screen -x fuzz"
|
||||
echo "connect to the fuzz_tests using: screen -x fuzz"
|
||||
echo "if fuzzing doesn't start execute the following as root:"
|
||||
echo ""
|
||||
echo "echo core >/proc/sys/kernel/core_pattern"
|
||||
echo "echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor"
|
||||
|
||||
# Main fuzzer, keeps complete corpus
|
||||
screen -dmS fuzz afl-fuzz -M fuzz0 "$AFL_ARGS" -c ./_afl_build_cmplog/bootstrap_fuzzer ./_afl_build/bootstrap_fuzzer
|
||||
# Main fuzz_test, keeps complete corpus
|
||||
screen -dmS fuzz afl-fuzz -M fuzz0 "$AFL_ARGS" -c ./_afl_build_cmplog/bootstrap_fuzz_test ./_afl_build/bootstrap_fuzz_test
|
||||
sleep 10s
|
||||
|
||||
# Secondary fuzzers
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz1 "$AFL_ARGS" -- ./_afl_build_msan/bootstrap_fuzzer
|
||||
# Secondary fuzz_tests
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz1 "$AFL_ARGS" -- ./_afl_build_msan/bootstrap_fuzz_test
|
||||
sleep 1s
|
||||
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz2 "$AFL_ARGS" ./_afl_build_ubsan/bootstrap_fuzzer
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz2 "$AFL_ARGS" ./_afl_build_ubsan/bootstrap_fuzz_test
|
||||
sleep 1s
|
||||
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz3 "$AFL_ARGS" ./_afl_build_asan/bootstrap_fuzzer
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz3 "$AFL_ARGS" ./_afl_build_asan/bootstrap_fuzz_test
|
||||
|
Reference in New Issue
Block a user