mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
test: Add a protocol dump test to generate initial fuzzer input.
This commit is contained in:
parent
3a5da3588f
commit
50094b7385
|
@ -226,17 +226,24 @@ static void initialise_autotox(struct Tox_Options *options, AutoTox *autotox, ui
|
|||
options = default_opts;
|
||||
}
|
||||
|
||||
// Try a few ports for the TCP relay.
|
||||
for (uint16_t tcp_port = autotest_opts->tcp_port; tcp_port < autotest_opts->tcp_port + 200; ++tcp_port) {
|
||||
tox_options_set_tcp_port(options, tcp_port);
|
||||
if (tox_options_get_udp_enabled(options)) {
|
||||
tox_options_set_tcp_port(options, 0);
|
||||
autotest_opts->tcp_port = 0;
|
||||
autotox->tox = tox_new_log(options, &err, &autotox->index);
|
||||
ck_assert_msg(err == TOX_ERR_NEW_OK, "unexpected tox_new error: %d", err);
|
||||
} else {
|
||||
// Try a few ports for the TCP relay.
|
||||
for (uint16_t tcp_port = autotest_opts->tcp_port; tcp_port < autotest_opts->tcp_port + 200; ++tcp_port) {
|
||||
tox_options_set_tcp_port(options, tcp_port);
|
||||
autotox->tox = tox_new_log(options, &err, &autotox->index);
|
||||
|
||||
if (autotox->tox != nullptr) {
|
||||
autotest_opts->tcp_port = tcp_port;
|
||||
break;
|
||||
if (autotox->tox != nullptr) {
|
||||
autotest_opts->tcp_port = tcp_port;
|
||||
break;
|
||||
}
|
||||
|
||||
ck_assert_msg(err == TOX_ERR_NEW_PORT_ALLOC, "unexpected tox_new error (expected PORT_ALLOC): %d", err);
|
||||
}
|
||||
|
||||
ck_assert_msg(err == TOX_ERR_NEW_PORT_ALLOC, "unexpected tox_new error (expected PORT_ALLOC): %d", err);
|
||||
}
|
||||
|
||||
tox_options_free(default_opts);
|
||||
|
@ -322,6 +329,7 @@ static void bootstrap_autotoxes(struct Tox_Options *options, uint32_t tox_count,
|
|||
}
|
||||
|
||||
if (!udp_enabled) {
|
||||
ck_assert(autotest_opts->tcp_port != 0);
|
||||
printf("bootstrapping all toxes to local TCP relay running on port %d\n", autotest_opts->tcp_port);
|
||||
|
||||
for (uint32_t i = 0; i < tox_count; ++i) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
c336ec34a4f17601b4bea707acd7162b76e0693ca044715cdb4d6646709cdb39 /usr/local/bin/tox-bootstrapd
|
||||
5581c3dda4277afb002dcb6c047e6ebfe08a1d97ae9622c37f795002c0c22074 /usr/local/bin/tox-bootstrapd
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
|
||||
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
|
||||
load("@rules_fuzzing//fuzzing/private:binary.bzl", "fuzzing_binary") # buildifier: disable=bzl-visibility
|
||||
|
||||
package(features = ["layering_check"])
|
||||
|
||||
|
@ -32,10 +33,25 @@ cc_fuzz_test(
|
|||
corpus = ["//tools/toktok-fuzzer/corpus:bootstrap_fuzzer"],
|
||||
deps = [
|
||||
":fuzz_support",
|
||||
":fuzz_tox",
|
||||
"//c-toxcore/toxcore:tox",
|
||||
"//c-toxcore/toxcore:tox_dispatch",
|
||||
"//c-toxcore/toxcore:tox_events",
|
||||
],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "e2e_fuzz_test",
|
||||
srcs = ["e2e_fuzz_test.cc"],
|
||||
copts = ["-UNDEBUG"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:e2e_fuzz_test"],
|
||||
data = ["//tools/toktok-fuzzer/init:e2e_fuzz_test.dat"],
|
||||
deps = [
|
||||
":fuzz_support",
|
||||
":fuzz_tox",
|
||||
"//c-toxcore/toxcore:tox",
|
||||
"//c-toxcore/toxcore:tox_dispatch",
|
||||
"//c-toxcore/toxcore:tox_events",
|
||||
"//c-toxcore/toxcore:util",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -49,3 +65,37 @@ cc_fuzz_test(
|
|||
"//c-toxcore/toxcore:tox",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "protodump",
|
||||
srcs = ["protodump.cc"],
|
||||
copts = ["-UNDEBUG"],
|
||||
deps = [
|
||||
":fuzz_support",
|
||||
"//c-toxcore/toxcore:tox",
|
||||
"//c-toxcore/toxcore:tox_dispatch",
|
||||
"//c-toxcore/toxcore:tox_events",
|
||||
"//c-toxcore/toxcore:util",
|
||||
],
|
||||
)
|
||||
|
||||
fuzzing_binary(
|
||||
name = "protodump_bin",
|
||||
testonly = True,
|
||||
binary = ":protodump",
|
||||
engine = "@rules_fuzzing//fuzzing:cc_engine",
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "protodump_reduce",
|
||||
srcs = ["protodump_reduce.cc"],
|
||||
copts = ["-UNDEBUG"],
|
||||
deps = [
|
||||
":fuzz_support",
|
||||
":fuzz_tox",
|
||||
"//c-toxcore/toxcore:tox",
|
||||
"//c-toxcore/toxcore:tox_dispatch",
|
||||
"//c-toxcore/toxcore:tox_events",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <cstdio>
|
||||
|
||||
#include "../../toxcore/tox.h"
|
||||
#include "../../toxcore/tox_dispatch.h"
|
||||
#include "../../toxcore/tox_events.h"
|
||||
#include "../../toxcore/tox_private.h"
|
||||
#include "../../toxcore/tox_struct.h"
|
||||
#include "../../toxcore/util.h"
|
||||
#include "fuzz_support.h"
|
||||
#include "fuzz_tox.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -111,28 +108,36 @@ void setup_callbacks(Tox_Dispatch *dispatch)
|
|||
void TestBootstrap(Fuzz_Data &input)
|
||||
{
|
||||
Fuzz_System sys(input);
|
||||
assert(sys.rng != nullptr);
|
||||
|
||||
Tox_Options *opts = tox_options_new(nullptr);
|
||||
Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free);
|
||||
assert(opts != nullptr);
|
||||
tox_options_set_operating_system(opts, sys.sys.get());
|
||||
tox_options_set_operating_system(opts.get(), sys.sys.get());
|
||||
|
||||
tox_options_set_log_callback(opts.get(),
|
||||
[](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) {
|
||||
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
|
||||
func, message);
|
||||
}
|
||||
});
|
||||
|
||||
CONSUME1_OR_RETURN(const uint8_t proxy_type, input);
|
||||
if (proxy_type == 0) {
|
||||
tox_options_set_proxy_type(opts, TOX_PROXY_TYPE_NONE);
|
||||
tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_NONE);
|
||||
} else if (proxy_type == 1) {
|
||||
tox_options_set_proxy_type(opts, TOX_PROXY_TYPE_SOCKS5);
|
||||
tox_options_set_proxy_host(opts, "127.0.0.1");
|
||||
tox_options_set_proxy_port(opts, 8080);
|
||||
tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_SOCKS5);
|
||||
tox_options_set_proxy_host(opts.get(), "127.0.0.1");
|
||||
tox_options_set_proxy_port(opts.get(), 8080);
|
||||
} else if (proxy_type == 2) {
|
||||
tox_options_set_proxy_type(opts, TOX_PROXY_TYPE_HTTP);
|
||||
tox_options_set_proxy_host(opts, "127.0.0.1");
|
||||
tox_options_set_proxy_port(opts, 8080);
|
||||
tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_HTTP);
|
||||
tox_options_set_proxy_host(opts.get(), "127.0.0.1");
|
||||
tox_options_set_proxy_port(opts.get(), 8080);
|
||||
}
|
||||
|
||||
Tox_Err_New error_new;
|
||||
Tox *tox = tox_new(opts, &error_new);
|
||||
tox_options_free(opts);
|
||||
Tox *tox = tox_new(opts.get(), &error_new);
|
||||
|
||||
if (tox == nullptr) {
|
||||
// It might fail, because some I/O happens in tox_new, and the fuzzer
|
||||
|
@ -144,10 +149,10 @@ void TestBootstrap(Fuzz_Data &input)
|
|||
|
||||
uint8_t pub_key[TOX_PUBLIC_KEY_SIZE] = {0};
|
||||
|
||||
const bool udp_success = tox_bootstrap(tox, "127.0.0.1", 12345, pub_key, nullptr);
|
||||
const bool udp_success = tox_bootstrap(tox, "127.0.0.2", 33446, pub_key, nullptr);
|
||||
assert(udp_success);
|
||||
|
||||
const bool tcp_success = tox_add_tcp_relay(tox, "127.0.0.1", 12345, pub_key, nullptr);
|
||||
const bool tcp_success = tox_add_tcp_relay(tox, "127.0.0.2", 33446, pub_key, nullptr);
|
||||
assert(tcp_success);
|
||||
|
||||
tox_events_init(tox);
|
||||
|
|
213
testing/fuzzing/e2e_fuzz_test.cc
Normal file
213
testing/fuzzing/e2e_fuzz_test.cc
Normal file
|
@ -0,0 +1,213 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "../../toxcore/tox.h"
|
||||
#include "../../toxcore/tox_dispatch.h"
|
||||
#include "../../toxcore/tox_events.h"
|
||||
#include "fuzz_support.h"
|
||||
#include "fuzz_tox.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) {
|
||||
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);
|
||||
});
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
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) {
|
||||
// OK: friend came online.
|
||||
const uint32_t friend_number
|
||||
= tox_event_friend_connection_status_get_friend_number(event);
|
||||
assert(friend_number != UINT32_MAX);
|
||||
});
|
||||
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);
|
||||
});
|
||||
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);
|
||||
});
|
||||
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);
|
||||
const uint32_t message_length = tox_event_friend_message_get_message_length(event);
|
||||
const uint8_t *message = tox_event_friend_message_get_message(event);
|
||||
tox_friend_send_message(tox, friend_number, type, message, message_length, nullptr);
|
||||
});
|
||||
tox_events_callback_friend_name(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Name *event, void *user_data) {
|
||||
// OK: friend name received.
|
||||
});
|
||||
tox_events_callback_friend_read_receipt(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Read_Receipt *event, void *user_data) {
|
||||
// OK: message has been received.
|
||||
});
|
||||
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.
|
||||
});
|
||||
tox_events_callback_friend_status_message(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Status_Message *event, void *user_data) {
|
||||
// OK: friend status message received.
|
||||
});
|
||||
tox_events_callback_friend_typing(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Typing *event, void *user_data) {
|
||||
// OK: friend may be typing.
|
||||
});
|
||||
tox_events_callback_self_connection_status(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Self_Connection_Status *event, void *user_data) {
|
||||
// OK: we got connected.
|
||||
});
|
||||
}
|
||||
|
||||
void TestEndToEnd(Fuzz_Data &input)
|
||||
{
|
||||
Fuzz_System sys(input);
|
||||
|
||||
Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free);
|
||||
assert(opts != nullptr);
|
||||
tox_options_set_operating_system(opts.get(), sys.sys.get());
|
||||
tox_options_set_local_discovery_enabled(opts.get(), false);
|
||||
|
||||
tox_options_set_log_callback(opts.get(),
|
||||
[](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) {
|
||||
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
|
||||
func, message);
|
||||
}
|
||||
});
|
||||
|
||||
Tox_Err_New error_new;
|
||||
Tox *tox = tox_new(opts.get(), &error_new);
|
||||
|
||||
if (tox == nullptr) {
|
||||
// It might fail, because some I/O happens in tox_new, and the fuzzer
|
||||
// might do things that make that I/O fail.
|
||||
return;
|
||||
}
|
||||
|
||||
assert(error_new == TOX_ERR_NEW_OK);
|
||||
|
||||
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 decent amount so all the time-based checks
|
||||
// trigger more quickly.
|
||||
sys.clock += std::max(System::MIN_ITERATION_INTERVAL, random_u08(sys.rng.get()));
|
||||
}
|
||||
|
||||
tox_dispatch_free(dispatch);
|
||||
tox_kill(tox);
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> startup_data = [] {
|
||||
constexpr char startup_file[] = "tools/toktok-fuzzer/init/e2e_fuzz_test.dat";
|
||||
|
||||
struct stat statbuf;
|
||||
const int res = stat(startup_file, &statbuf);
|
||||
assert(res == 0);
|
||||
const int fd = open(startup_file, O_RDONLY);
|
||||
assert(fd > 0);
|
||||
|
||||
std::vector<uint8_t> data(statbuf.st_size);
|
||||
|
||||
const ssize_t read_count = read(fd, data.data(), data.size());
|
||||
assert(read_count > 0 && read_count == statbuf.st_size);
|
||||
return data;
|
||||
}();
|
||||
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
std::vector<uint8_t> full_data(startup_data.size() + size);
|
||||
std::copy(startup_data.begin(), startup_data.end(), full_data.begin());
|
||||
std::copy(data, data + size, full_data.begin() + startup_data.size());
|
||||
|
||||
Fuzz_Data input{full_data.data(), full_data.size()};
|
||||
TestEndToEnd(input);
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
|
@ -8,7 +8,10 @@
|
|||
#include <sys/socket.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
|
@ -17,15 +20,20 @@
|
|||
#include "../../toxcore/tox_private.h"
|
||||
#include "func_conversion.h"
|
||||
|
||||
const bool DEBUG = false;
|
||||
|
||||
// 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)
|
||||
System::~System() { }
|
||||
|
||||
static int recv_common(Fuzz_Data &input, uint8_t *buf, size_t buf_len)
|
||||
{
|
||||
if (input.size < 2) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -33,9 +41,21 @@ static int recv_common(Fuzz_Data &input, void *buf, size_t buf_len)
|
|||
input.data += 2;
|
||||
input.size -= 2;
|
||||
|
||||
if (fuzz_len == 0xffff) {
|
||||
errno = EWOULDBLOCK;
|
||||
if (DEBUG) {
|
||||
std::printf("recvfrom: no data for tox1\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::printf(
|
||||
"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));
|
||||
|
||||
memcpy(buf, input.data, res);
|
||||
std::copy(input.data, input.data + res, buf);
|
||||
input.data += res;
|
||||
input.size -= res;
|
||||
|
||||
|
@ -43,53 +63,59 @@ static int recv_common(Fuzz_Data &input, void *buf, size_t buf_len)
|
|||
}
|
||||
|
||||
static constexpr 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; },
|
||||
/* .close = */ ![](Fuzz_System *self, int sock) { return 0; },
|
||||
/* .accept = */ ![](Fuzz_System *self, int sock) { return 1337; },
|
||||
/* .bind = */ ![](Fuzz_System *self, int sock, const Network_Addr *addr) { return 0; },
|
||||
/* .listen = */ ![](Fuzz_System *self, int sock, int backlog) { return 0; },
|
||||
/* .recvbuf = */
|
||||
![](Fuzz_System *self, int sock) {
|
||||
assert(sock == 42);
|
||||
const size_t count = random_u16(self->rng.get());
|
||||
return static_cast<int>(std::min(count, self->data.size));
|
||||
},
|
||||
/* .recv = */
|
||||
![](Fuzz_System *self, int sock, uint8_t *buf, size_t len) {
|
||||
assert(sock == 42);
|
||||
// Receive data from the fuzzer.
|
||||
return recv_common(self->data, buf, len);
|
||||
},
|
||||
/* .recvfrom = */
|
||||
![](Fuzz_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
|
||||
assert(sock == 42);
|
||||
|
||||
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<sockaddr_in *>(&addr->addr);
|
||||
addr_in->sin_port = 12356;
|
||||
addr_in->sin_addr.s_addr = INADDR_LOOPBACK + 1;
|
||||
addr_in->sin_port = htons(33446);
|
||||
addr_in->sin_addr.s_addr = htonl(0x7f000002); // 127.0.0.2
|
||||
addr->size = sizeof(struct sockaddr);
|
||||
|
||||
return recv_common(self->data, buf, len);
|
||||
},
|
||||
/* .send = */
|
||||
[](void *obj, int sock, const uint8_t *buf, size_t len) {
|
||||
![](Fuzz_System *self, int sock, const uint8_t *buf, size_t len) {
|
||||
assert(sock == 42);
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .sendto = */
|
||||
[](void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
|
||||
![](Fuzz_System *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
|
||||
assert(sock == 42);
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .socket = */ [](void *obj, int domain, int type, int proto) { return 1; },
|
||||
/* .socket_nonblock = */ [](void *obj, int sock, bool nonblock) { return 0; },
|
||||
/* .socket = */ ![](Fuzz_System *self, int domain, int type, int proto) { return 42; },
|
||||
/* .socket_nonblock = */ ![](Fuzz_System *self, int sock, bool nonblock) { return 0; },
|
||||
/* .getsockopt = */
|
||||
[](void *obj, int sock, int level, int optname, void *optval, size_t *optlen) {
|
||||
memset(optval, 0, *optlen);
|
||||
![](Fuzz_System *self, int sock, int level, int optname, void *optval, size_t *optlen) {
|
||||
std::memset(optval, 0, *optlen);
|
||||
return 0;
|
||||
},
|
||||
/* .setsockopt = */
|
||||
[](void *obj, int sock, int level, int optname, const void *optval, size_t optlen) {
|
||||
![](Fuzz_System *self, int sock, int level, int optname, const void *optval, size_t optlen) {
|
||||
return 0;
|
||||
},
|
||||
};
|
||||
|
@ -101,9 +127,12 @@ static constexpr Random_Funcs fuzz_random_funcs = {
|
|||
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::memcpy(bytes, self->data.data, bytes_read);
|
||||
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);
|
||||
}
|
||||
},
|
||||
/* .random_uniform = */
|
||||
![](Fuzz_System *self, uint32_t upper_bound) {
|
||||
|
@ -118,10 +147,12 @@ static constexpr Random_Funcs fuzz_random_funcs = {
|
|||
};
|
||||
|
||||
Fuzz_System::Fuzz_System(Fuzz_Data &input)
|
||||
: data(input)
|
||||
, sys(std::make_unique<Tox_System>())
|
||||
, ns(std::make_unique<Network>(Network{&fuzz_network_funcs, this}))
|
||||
, rng(std::make_unique<Random>(Random{&fuzz_random_funcs, this}))
|
||||
: System{
|
||||
std::make_unique<Tox_System>(),
|
||||
std::make_unique<Network>(Network{&fuzz_network_funcs, this}),
|
||||
std::make_unique<Random>(Random{&fuzz_random_funcs, this}),
|
||||
}
|
||||
, data(input)
|
||||
{
|
||||
sys->mono_time_callback = ![](Fuzz_System *self) { return self->clock; };
|
||||
sys->mono_time_user_data = this;
|
||||
|
@ -129,43 +160,43 @@ Fuzz_System::Fuzz_System(Fuzz_Data &input)
|
|||
sys->rng = rng.get();
|
||||
}
|
||||
|
||||
Fuzz_System::~Fuzz_System() { }
|
||||
|
||||
static constexpr Network_Funcs null_network_funcs = {
|
||||
/* .close = */ [](void *obj, int sock) { return 0; },
|
||||
/* .accept = */ [](void *obj, int sock) { return 2; },
|
||||
/* .bind = */ [](void *obj, int sock, const Network_Addr *addr) { return 0; },
|
||||
/* .listen = */ [](void *obj, int sock, int backlog) { return 0; },
|
||||
/* .close = */ ![](Null_System *self, int sock) { return 0; },
|
||||
/* .accept = */ ![](Null_System *self, int sock) { return 1337; },
|
||||
/* .bind = */ ![](Null_System *self, int sock, const Network_Addr *addr) { return 0; },
|
||||
/* .listen = */ ![](Null_System *self, int sock, int backlog) { return 0; },
|
||||
/* .recvbuf = */ ![](Null_System *self, int sock) { return 0; },
|
||||
/* .recv = */
|
||||
![](Null_System *self, int sock, uint8_t *buf, size_t len) {
|
||||
// Always fail.
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
},
|
||||
/* .recvfrom = */
|
||||
![](Null_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
|
||||
// Always fail.
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
},
|
||||
/* .send = */
|
||||
[](void *obj, int sock, const uint8_t *buf, size_t len) {
|
||||
![](Null_System *self, int sock, const uint8_t *buf, size_t len) {
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .sendto = */
|
||||
[](void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
|
||||
![](Null_System *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .socket = */ [](void *obj, int domain, int type, int proto) { return 1; },
|
||||
/* .socket_nonblock = */ [](void *obj, int sock, bool nonblock) { return 0; },
|
||||
/* .socket = */ ![](Null_System *self, int domain, int type, int proto) { return 42; },
|
||||
/* .socket_nonblock = */ ![](Null_System *self, int sock, bool nonblock) { return 0; },
|
||||
/* .getsockopt = */
|
||||
[](void *obj, int sock, int level, int optname, void *optval, size_t *optlen) {
|
||||
memset(optval, 0, *optlen);
|
||||
![](Null_System *self, int sock, int level, int optname, void *optval, size_t *optlen) {
|
||||
std::memset(optval, 0, *optlen);
|
||||
return 0;
|
||||
},
|
||||
/* .setsockopt = */
|
||||
[](void *obj, int sock, int level, int optname, const void *optval, size_t optlen) {
|
||||
![](Null_System *self, int sock, int level, int optname, const void *optval, size_t optlen) {
|
||||
return 0;
|
||||
},
|
||||
};
|
||||
|
@ -191,9 +222,11 @@ static constexpr Random_Funcs null_random_funcs = {
|
|||
};
|
||||
|
||||
Null_System::Null_System()
|
||||
: sys(std::make_unique<Tox_System>())
|
||||
, ns(std::make_unique<Network>(Network{&null_network_funcs, this}))
|
||||
, rng(std::make_unique<Random>(Random{&null_random_funcs, this}))
|
||||
: System{
|
||||
std::make_unique<Tox_System>(),
|
||||
std::make_unique<Network>(Network{&null_network_funcs, this}),
|
||||
std::make_unique<Random>(Random{&null_random_funcs, this}),
|
||||
}
|
||||
{
|
||||
sys->mono_time_callback = ![](Fuzz_System *self) { return self->clock; };
|
||||
sys->mono_time_user_data = this;
|
||||
|
@ -201,4 +234,135 @@ Null_System::Null_System()
|
|||
sys->rng = rng.get();
|
||||
}
|
||||
|
||||
Null_System::~Null_System() { }
|
||||
static uint16_t get_port(const Network_Addr *addr)
|
||||
{
|
||||
if (addr->addr.ss_family == AF_INET6) {
|
||||
return reinterpret_cast<const sockaddr_in6 *>(&addr->addr)->sin6_port;
|
||||
} else {
|
||||
assert(addr->addr.ss_family == AF_INET);
|
||||
return reinterpret_cast<const sockaddr_in *>(&addr->addr)->sin_port;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr Network_Funcs record_network_funcs = {
|
||||
/* .close = */ ![](Record_System *self, int sock) { return 0; },
|
||||
/* .accept = */ ![](Record_System *self, int sock) { return 2; },
|
||||
/* .bind = */
|
||||
![](Record_System *self, int sock, const Network_Addr *addr) {
|
||||
const uint16_t port = get_port(addr);
|
||||
if (self->global_.bound.find(port) != self->global_.bound.end()) {
|
||||
errno = EADDRINUSE;
|
||||
return -1;
|
||||
}
|
||||
self->global_.bound.emplace(port, self);
|
||||
self->port = port;
|
||||
return 0;
|
||||
},
|
||||
/* .listen = */ ![](Record_System *self, int sock, int backlog) { return 0; },
|
||||
/* .recvbuf = */ ![](Record_System *self, int sock) { return 0; },
|
||||
/* .recv = */
|
||||
![](Record_System *self, int sock, uint8_t *buf, size_t len) {
|
||||
// Always fail.
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
},
|
||||
/* .recvfrom = */
|
||||
![](Record_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
|
||||
assert(sock == 42);
|
||||
if (self->recvq.empty()) {
|
||||
self->recording.push_back(0xff);
|
||||
self->recording.push_back(0xff);
|
||||
errno = EWOULDBLOCK;
|
||||
if (DEBUG) {
|
||||
std::printf("recvfrom: no data for %s\n", self->name_);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
const auto [from, packet] = std::move(self->recvq.front());
|
||||
self->recvq.pop_front();
|
||||
const size_t recvlen = std::min(len, packet.size());
|
||||
std::copy(packet.begin(), packet.end(), buf);
|
||||
|
||||
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<sockaddr_in *>(&addr->addr);
|
||||
addr_in->sin_port = from;
|
||||
addr_in->sin_addr.s_addr = htonl(0x7f000002); // 127.0.0.2
|
||||
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->recording.insert(self->recording.end(), buf, buf + recvlen);
|
||||
return static_cast<int>(recvlen);
|
||||
},
|
||||
/* .send = */
|
||||
![](Record_System *self, int sock, const uint8_t *buf, size_t len) {
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .sendto = */
|
||||
![](Record_System *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
|
||||
assert(sock == 42);
|
||||
auto backend = self->global_.bound.find(get_port(addr));
|
||||
assert(backend != self->global_.bound.end());
|
||||
backend->second->receive(self->port, buf, len);
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .socket = */ ![](Record_System *self, int domain, int type, int proto) { return 42; },
|
||||
/* .socket_nonblock = */ ![](Record_System *self, int sock, bool nonblock) { return 0; },
|
||||
/* .getsockopt = */
|
||||
![](Record_System *self, int sock, int level, int optname, void *optval, size_t *optlen) {
|
||||
std::memset(optval, 0, *optlen);
|
||||
return 0;
|
||||
},
|
||||
/* .setsockopt = */
|
||||
![](Record_System *self, int sock, int level, int optname, const void *optval, size_t optlen) {
|
||||
return 0;
|
||||
},
|
||||
};
|
||||
|
||||
static constexpr Random_Funcs record_random_funcs = {
|
||||
/* .random_bytes = */
|
||||
![](Record_System *self, uint8_t *bytes, size_t length) {
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
bytes[i] = simple_rng(self->seed_) & 0xff;
|
||||
self->recording.push_back(bytes[i]);
|
||||
}
|
||||
if (DEBUG) {
|
||||
std::printf(
|
||||
"rng: %02x..%02x[%zu] -> %s\n", bytes[0], bytes[length - 1], length, self->name_);
|
||||
}
|
||||
},
|
||||
/* .random_uniform = */
|
||||
fuzz_random_funcs.random_uniform,
|
||||
};
|
||||
|
||||
Record_System::Record_System(Global &global, uint64_t seed, const char *name)
|
||||
: System{
|
||||
std::make_unique<Tox_System>(),
|
||||
std::make_unique<Network>(Network{&record_network_funcs, this}),
|
||||
std::make_unique<Random>(Random{&record_random_funcs, this}),
|
||||
}
|
||||
, global_(global)
|
||||
, seed_(seed)
|
||||
, name_(name)
|
||||
{
|
||||
sys->mono_time_callback = ![](Fuzz_System *self) { return self->clock; };
|
||||
sys->mono_time_user_data = this;
|
||||
sys->ns = ns.get();
|
||||
sys->rng = rng.get();
|
||||
}
|
||||
|
||||
void Record_System::receive(uint16_t send_port, const uint8_t *buf, size_t len)
|
||||
{
|
||||
assert(port != 0);
|
||||
recvq.emplace_back(send_port, std::vector<uint8_t>{buf, buf + len});
|
||||
}
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "../../toxcore/tox.h"
|
||||
|
@ -100,20 +103,51 @@ void fuzz_select_target(const uint8_t *data, std::size_t size, Args &&... args)
|
|||
struct Network;
|
||||
struct Random;
|
||||
|
||||
struct System {
|
||||
std::unique_ptr<Tox_System> sys;
|
||||
std::unique_ptr<Network> ns;
|
||||
std::unique_ptr<Random> rng;
|
||||
|
||||
// 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
|
||||
* clock time that should be advanced more quickly in the test.
|
||||
*/
|
||||
static constexpr uint8_t BOOTSTRAP_ITERATION_INTERVAL = 200;
|
||||
/**
|
||||
* Less than BOOTSTRAP_ITERATION_INTERVAL because otherwise we'll spam
|
||||
* onion announce packets.
|
||||
*/
|
||||
static constexpr uint8_t MESSAGE_ITERATION_INTERVAL = 20;
|
||||
/**
|
||||
* Move the clock forward at least 20ms so at least some amount of
|
||||
* time passes on each iteration.
|
||||
*/
|
||||
static constexpr uint8_t MIN_ITERATION_INTERVAL = 20;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Tox_System implementation that consumes fuzzer input to produce network
|
||||
* inputs and random numbers. Once it runs out of fuzzer input, network receive
|
||||
* functions return no more data and the random numbers are always zero.
|
||||
*/
|
||||
struct Fuzz_System {
|
||||
uint64_t clock = 0;
|
||||
struct Fuzz_System : System {
|
||||
Fuzz_Data &data;
|
||||
std::unique_ptr<Tox_System> sys;
|
||||
std::unique_ptr<Network> ns;
|
||||
std::unique_ptr<Random> rng;
|
||||
|
||||
explicit Fuzz_System(Fuzz_Data &input);
|
||||
~Fuzz_System();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -121,15 +155,76 @@ struct Fuzz_System {
|
|||
* working and deterministic RNG. Network receive functions always fail, send
|
||||
* always succeeds.
|
||||
*/
|
||||
struct Null_System {
|
||||
uint64_t clock = 0;
|
||||
struct Null_System : System {
|
||||
uint64_t seed = 4; // chosen by fair dice roll. guaranteed to be random.
|
||||
std::unique_ptr<Tox_System> sys;
|
||||
std::unique_ptr<Network> ns;
|
||||
std::unique_ptr<Random> rng;
|
||||
|
||||
Null_System();
|
||||
~Null_System();
|
||||
};
|
||||
|
||||
/**
|
||||
* A Tox_System implementation that records all I/O but does not actually
|
||||
* perform any real I/O. Everything inside this system is hermetic in-process
|
||||
* and fully deterministic.
|
||||
*
|
||||
* Note: take care not to initialise two systems with the same seed, since
|
||||
* that's the only thing distinguishing the system's behaviour. Two toxes
|
||||
* initialised with the same seed will be identical (same keys, etc.).
|
||||
*/
|
||||
struct Record_System : System {
|
||||
/** @brief State shared between all tox instances. */
|
||||
struct Global {
|
||||
/** @brief Bound UDP ports and their system instance.
|
||||
*
|
||||
* This implements an in-process network where instances can send
|
||||
* packets to other instances by inserting them into the receiver's
|
||||
* recvq using the receive function.
|
||||
*
|
||||
* We need to keep track of ports associated with recv queues because
|
||||
* toxcore sends packets to itself sometimes when doing onion routing
|
||||
* with only 2 nodes in the network.
|
||||
*/
|
||||
std::unordered_map<uint16_t, Record_System *> bound;
|
||||
};
|
||||
|
||||
Global &global_;
|
||||
uint64_t seed_; //!< Current PRNG state.
|
||||
const char *name_; //!< Tox system name ("tox1"/"tox2") for logging.
|
||||
|
||||
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);
|
||||
|
||||
/** @brief Deposit a network packet in this instance's recvq.
|
||||
*/
|
||||
void receive(uint16_t send_port, const uint8_t *buf, size_t len);
|
||||
};
|
||||
|
||||
/** @brief Enable debug logging.
|
||||
*
|
||||
* This should not be enabled in fuzzer code while fuzzing, as console I/O slows
|
||||
* everything down drastically. It's useful while developing the fuzzer and the
|
||||
* protodump program.
|
||||
*/
|
||||
extern const bool DEBUG;
|
||||
|
||||
inline constexpr char tox_log_level_name(Tox_Log_Level level)
|
||||
{
|
||||
switch (level) {
|
||||
case TOX_LOG_LEVEL_TRACE:
|
||||
return 'T';
|
||||
case TOX_LOG_LEVEL_DEBUG:
|
||||
return 'D';
|
||||
case TOX_LOG_LEVEL_INFO:
|
||||
return 'I';
|
||||
case TOX_LOG_LEVEL_WARNING:
|
||||
return 'W';
|
||||
case TOX_LOG_LEVEL_ERROR:
|
||||
return 'E';
|
||||
}
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
#endif // C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
|
||||
|
|
315
testing/fuzzing/protodump.cc
Normal file
315
testing/fuzzing/protodump.cc
Normal file
|
@ -0,0 +1,315 @@
|
|||
/** @file
|
||||
* @brief Generates a valid input for e2e_fuzz_test.
|
||||
*
|
||||
* This bootstraps 2 toxes tox1 and tox2, adds tox1 as tox2's friend, waits for
|
||||
* the friend request, then tox1 adds tox2 in response, waits for the friend to
|
||||
* come online, sends a 2-message exchange, and waits for the read receipt.
|
||||
*
|
||||
* All random inputs and network traffic is recorded and dumped to files at the
|
||||
* end. This can then be fed to e2e_fuzz_test for replay (only of tox1) and
|
||||
* further code path exploration using fuzzer mutations.
|
||||
*
|
||||
* We write 2 files: an init file that contains all the inputs needed to reach
|
||||
* the "friend online" state, and a smaller file containing things to mutate
|
||||
* once the tox instance is in that state. This allows for more specific
|
||||
* exploration of code paths starting from "friend is online". DHT and onion
|
||||
* packet parsing is explored more in bootstrap_fuzz_test.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* bazel build //c-toxcore/testing/fuzzing:protodump_bin && \
|
||||
* bazel-bin/c-toxcore/testing/fuzzing/protodump_bin
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
#include "../../toxcore/tox.h"
|
||||
#include "../../toxcore/tox_dispatch.h"
|
||||
#include "../../toxcore/tox_events.h"
|
||||
#include "../../toxcore/tox_private.h"
|
||||
#include "../../toxcore/tox_struct.h"
|
||||
#include "../../toxcore/util.h"
|
||||
#include "fuzz_support.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/** @brief Number of messages to exchange between tox1 and tox2.
|
||||
*
|
||||
* The higher this number, the more room we give the fuzzer to mutate the
|
||||
* exchange into something more interesting. If it's too high, the fuzzer will
|
||||
* be slow.
|
||||
*/
|
||||
constexpr uint32_t MESSAGE_COUNT = 5;
|
||||
|
||||
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) {
|
||||
// OK: friend came online.
|
||||
const uint32_t friend_number
|
||||
= tox_event_friend_connection_status_get_friend_number(event);
|
||||
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) {
|
||||
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) {
|
||||
const uint32_t friend_number = tox_event_friend_message_get_friend_number(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);
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
// OK: we got connected.
|
||||
});
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
Record_System::Global global;
|
||||
|
||||
Tox_Options *opts = tox_options_new(nullptr);
|
||||
assert(opts != nullptr);
|
||||
|
||||
tox_options_set_local_discovery_enabled(opts, false);
|
||||
|
||||
tox_options_set_log_callback(opts,
|
||||
[](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
|
||||
const char *message, void *user_data) {
|
||||
// Log to stdout.
|
||||
std::printf("[%s] %c %s:%d(%s): %s\n", static_cast<Record_System *>(user_data)->name_,
|
||||
tox_log_level_name(level), file, line, func, message);
|
||||
});
|
||||
|
||||
Tox_Err_New error_new;
|
||||
|
||||
Record_System sys1(global, 4, "tox1"); // fair dice roll
|
||||
tox_options_set_log_user_data(opts, &sys1);
|
||||
tox_options_set_operating_system(opts, sys1.sys.get());
|
||||
Tox *tox1 = tox_new(opts, &error_new);
|
||||
assert(tox1 != nullptr);
|
||||
assert(error_new == TOX_ERR_NEW_OK);
|
||||
std::array<uint8_t, TOX_ADDRESS_SIZE> address1;
|
||||
tox_self_get_address(tox1, address1.data());
|
||||
std::array<uint8_t, TOX_PUBLIC_KEY_SIZE> pk1;
|
||||
tox_self_get_public_key(tox1, pk1.data());
|
||||
std::array<uint8_t, TOX_PUBLIC_KEY_SIZE> dht_key1;
|
||||
tox_self_get_dht_id(tox1, dht_key1.data());
|
||||
|
||||
Record_System sys2(global, 5, "tox2"); // unfair dice roll
|
||||
tox_options_set_log_user_data(opts, &sys2);
|
||||
tox_options_set_operating_system(opts, sys2.sys.get());
|
||||
Tox *tox2 = tox_new(opts, &error_new);
|
||||
assert(tox2 != nullptr);
|
||||
assert(error_new == TOX_ERR_NEW_OK);
|
||||
std::array<uint8_t, TOX_ADDRESS_SIZE> address2;
|
||||
tox_self_get_address(tox2, address2.data());
|
||||
std::array<uint8_t, TOX_PUBLIC_KEY_SIZE> pk2;
|
||||
tox_self_get_public_key(tox2, pk2.data());
|
||||
std::array<uint8_t, TOX_PUBLIC_KEY_SIZE> dht_key2;
|
||||
tox_self_get_dht_id(tox2, dht_key2.data());
|
||||
|
||||
assert(address1 != address2);
|
||||
assert(pk1 != pk2);
|
||||
assert(dht_key1 != dht_key2);
|
||||
|
||||
tox_options_free(opts);
|
||||
|
||||
const uint16_t port = tox_self_get_udp_port(tox1, nullptr);
|
||||
|
||||
const bool udp_success = tox_bootstrap(tox2, "127.0.0.2", port, dht_key1.data(), nullptr);
|
||||
assert(udp_success);
|
||||
|
||||
tox_events_init(tox1);
|
||||
tox_events_init(tox2);
|
||||
|
||||
Tox_Dispatch *dispatch = tox_dispatch_new(nullptr);
|
||||
assert(dispatch != nullptr);
|
||||
setup_callbacks(dispatch);
|
||||
|
||||
uint32_t done1 = 0;
|
||||
uint32_t done2 = 0;
|
||||
|
||||
const auto iterate = [&](uint8_t clock_increment) {
|
||||
Tox_Err_Events_Iterate error_iterate;
|
||||
Tox_Events *events;
|
||||
|
||||
events = tox_events_iterate(tox1, true, &error_iterate);
|
||||
assert(tox_events_equal(events, events));
|
||||
tox_dispatch_invoke(dispatch, events, tox1, &done1);
|
||||
tox_events_free(events);
|
||||
|
||||
events = tox_events_iterate(tox2, true, &error_iterate);
|
||||
assert(tox_events_equal(events, events));
|
||||
tox_dispatch_invoke(dispatch, events, tox2, &done2);
|
||||
tox_events_free(events);
|
||||
|
||||
// Move the clock forward a decent amount so all the time-based checks
|
||||
// trigger more quickly.
|
||||
sys1.clock += clock_increment;
|
||||
sys2.clock += clock_increment;
|
||||
|
||||
sys1.recording.push_back(clock_increment);
|
||||
sys2.recording.push_back(clock_increment);
|
||||
};
|
||||
|
||||
while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE
|
||||
|| tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE) {
|
||||
if (DEBUG) {
|
||||
std::printf("tox1: %d, tox2: %d\n", tox_self_get_connection_status(tox1),
|
||||
tox_self_get_connection_status(tox2));
|
||||
}
|
||||
iterate(System::BOOTSTRAP_ITERATION_INTERVAL);
|
||||
}
|
||||
|
||||
std::printf("toxes are online\n");
|
||||
|
||||
const uint8_t msg = 'A';
|
||||
const uint32_t friend_number = tox_friend_add(tox2, address1.data(), &msg, 1, nullptr);
|
||||
assert(friend_number == 0);
|
||||
|
||||
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) {
|
||||
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),
|
||||
tox_friend_get_connection_status(tox2, 0, nullptr));
|
||||
}
|
||||
iterate(System::BOOTSTRAP_ITERATION_INTERVAL);
|
||||
}
|
||||
|
||||
std::printf("tox clients connected\n");
|
||||
|
||||
dump(sys1.recording, "tools/toktok-fuzzer/init/e2e_fuzz_test.dat");
|
||||
|
||||
while (done1 < MESSAGE_COUNT && done2 < MESSAGE_COUNT) {
|
||||
if (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),
|
||||
tox_friend_get_connection_status(tox2, 0, nullptr));
|
||||
}
|
||||
iterate(System::MESSAGE_ITERATION_INTERVAL);
|
||||
}
|
||||
|
||||
std::printf("test complete\n");
|
||||
|
||||
tox_dispatch_free(dispatch);
|
||||
tox_kill(tox2);
|
||||
tox_kill(tox1);
|
||||
|
||||
dump(sys1.recording, "tools/toktok-fuzzer/corpus/e2e_fuzz_test/bootstrap.dat");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(void) { RecordBootstrap(); }
|
200
testing/fuzzing/protodump_reduce.cc
Normal file
200
testing/fuzzing/protodump_reduce.cc
Normal file
|
@ -0,0 +1,200 @@
|
|||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include "../../toxcore/tox.h"
|
||||
#include "../../toxcore/tox_dispatch.h"
|
||||
#include "../../toxcore/tox_events.h"
|
||||
#include "fuzz_support.h"
|
||||
#include "fuzz_tox.h"
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
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) {
|
||||
// OK: friend came online.
|
||||
const uint32_t friend_number
|
||||
= tox_event_friend_connection_status_get_friend_number(event);
|
||||
assert(friend_number != UINT32_MAX);
|
||||
});
|
||||
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);
|
||||
});
|
||||
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);
|
||||
});
|
||||
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);
|
||||
const uint32_t message_length = tox_event_friend_message_get_message_length(event);
|
||||
const uint8_t *message = tox_event_friend_message_get_message(event);
|
||||
tox_friend_send_message(tox, friend_number, type, message, message_length, nullptr);
|
||||
});
|
||||
tox_events_callback_friend_name(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Name *event, void *user_data) {
|
||||
// OK: friend name received.
|
||||
});
|
||||
tox_events_callback_friend_read_receipt(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Read_Receipt *event, void *user_data) {
|
||||
// OK: message has been received.
|
||||
});
|
||||
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.
|
||||
});
|
||||
tox_events_callback_friend_status_message(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Status_Message *event, void *user_data) {
|
||||
// OK: friend status message received.
|
||||
});
|
||||
tox_events_callback_friend_typing(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Typing *event, void *user_data) {
|
||||
// OK: friend may be typing.
|
||||
});
|
||||
tox_events_callback_self_connection_status(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Self_Connection_Status *event, void *user_data) {
|
||||
// OK: we got connected.
|
||||
});
|
||||
}
|
||||
|
||||
void TestEndToEnd(Fuzz_Data &input)
|
||||
{
|
||||
Fuzz_System sys(input);
|
||||
|
||||
Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free);
|
||||
assert(opts != nullptr);
|
||||
tox_options_set_operating_system(opts.get(), sys.sys.get());
|
||||
tox_options_set_local_discovery_enabled(opts.get(), false);
|
||||
|
||||
tox_options_set_log_callback(opts.get(),
|
||||
[](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) {
|
||||
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
|
||||
func, message);
|
||||
}
|
||||
});
|
||||
|
||||
Tox_Err_New error_new;
|
||||
Tox *tox = tox_new(opts.get(), &error_new);
|
||||
|
||||
if (tox == nullptr) {
|
||||
// It might fail, because some I/O happens in tox_new, and the fuzzer
|
||||
// might do things that make that I/O fail.
|
||||
return;
|
||||
}
|
||||
|
||||
assert(error_new == TOX_ERR_NEW_OK);
|
||||
|
||||
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);
|
||||
sys.clock += std::max(System::MIN_ITERATION_INTERVAL, random_u08(sys.rng.get()));
|
||||
}
|
||||
|
||||
if (REDUCE_PROTODUMP) {
|
||||
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));
|
||||
}
|
||||
|
||||
tox_dispatch_free(dispatch);
|
||||
tox_kill(tox);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
Fuzz_Data input{data, size};
|
||||
TestEndToEnd(input);
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
|
@ -472,7 +472,7 @@ int32_t crypto_new_keypair(const Random *rng, uint8_t *public_key, uint8_t *secr
|
|||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
random_bytes(rng, secret_key, CRYPTO_SECRET_KEY_SIZE);
|
||||
memset(public_key, 0, CRYPTO_PUBLIC_KEY_SIZE); // Make MSAN happy
|
||||
crypto_scalarmult_curve25519_base(public_key, secret_key);
|
||||
crypto_derive_public_key(public_key, secret_key);
|
||||
return 0;
|
||||
#else
|
||||
return crypto_box_keypair(public_key, secret_key);
|
||||
|
@ -492,13 +492,22 @@ void new_hmac_key(const Random *rng, uint8_t *key)
|
|||
void crypto_hmac(uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], const uint8_t *data,
|
||||
size_t length)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
memcpy(auth, key, 16);
|
||||
memcpy(auth + 16, data, length < 16 ? length : 16);
|
||||
#else
|
||||
crypto_auth(auth, data, length, key);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool crypto_hmac_verify(const uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE],
|
||||
const uint8_t *data, size_t length)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
return memcmp(auth, key, 16) == 0 && memcmp(auth + 16, data, length < 16 ? length : 16) == 0;
|
||||
#else
|
||||
return crypto_auth_verify(auth, data, length, key) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length)
|
||||
|
|
|
@ -655,6 +655,122 @@ static uint32_t data_1(uint16_t buflen, const uint8_t *buffer)
|
|||
return data;
|
||||
}
|
||||
|
||||
static const char *net_packet_type_name(Net_Packet_Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case NET_PACKET_PING_REQUEST:
|
||||
return "PING_REQUEST";
|
||||
|
||||
case NET_PACKET_PING_RESPONSE:
|
||||
return "PING_RESPONSE";
|
||||
|
||||
case NET_PACKET_GET_NODES:
|
||||
return "GET_NODES";
|
||||
|
||||
case NET_PACKET_SEND_NODES_IPV6:
|
||||
return "SEND_NODES_IPV6";
|
||||
|
||||
case NET_PACKET_COOKIE_REQUEST:
|
||||
return "COOKIE_REQUEST";
|
||||
|
||||
case NET_PACKET_COOKIE_RESPONSE:
|
||||
return "COOKIE_RESPONSE";
|
||||
|
||||
case NET_PACKET_CRYPTO_HS:
|
||||
return "CRYPTO_HS";
|
||||
|
||||
case NET_PACKET_CRYPTO_DATA:
|
||||
return "CRYPTO_DATA";
|
||||
|
||||
case NET_PACKET_CRYPTO:
|
||||
return "CRYPTO";
|
||||
|
||||
case NET_PACKET_LAN_DISCOVERY:
|
||||
return "LAN_DISCOVERY";
|
||||
|
||||
// TODO(Jfreegman): Uncomment these when we merge the rest of new groupchats
|
||||
// case NET_PACKET_GC_HANDSHAKE:
|
||||
// return "GC_HANDSHAKE";
|
||||
|
||||
// case NET_PACKET_GC_LOSSLESS:
|
||||
// return "GC_LOSSLESS";
|
||||
|
||||
// case NET_PACKET_GC_LOSSY:
|
||||
// return "GC_LOSSY";
|
||||
|
||||
case NET_PACKET_ONION_SEND_INITIAL:
|
||||
return "ONION_SEND_INITIAL";
|
||||
|
||||
case NET_PACKET_ONION_SEND_1:
|
||||
return "ONION_SEND_1";
|
||||
|
||||
case NET_PACKET_ONION_SEND_2:
|
||||
return "ONION_SEND_2";
|
||||
|
||||
case NET_PACKET_ANNOUNCE_REQUEST_OLD:
|
||||
return "ANNOUNCE_REQUEST_OLD";
|
||||
|
||||
case NET_PACKET_ANNOUNCE_RESPONSE_OLD:
|
||||
return "ANNOUNCE_RESPONSE_OLD";
|
||||
|
||||
case NET_PACKET_ONION_DATA_REQUEST:
|
||||
return "ONION_DATA_REQUEST";
|
||||
|
||||
case NET_PACKET_ONION_DATA_RESPONSE:
|
||||
return "ONION_DATA_RESPONSE";
|
||||
|
||||
case NET_PACKET_ANNOUNCE_REQUEST:
|
||||
return "ANNOUNCE_REQUEST";
|
||||
|
||||
case NET_PACKET_ANNOUNCE_RESPONSE:
|
||||
return "ANNOUNCE_RESPONSE";
|
||||
|
||||
case NET_PACKET_ONION_RECV_3:
|
||||
return "ONION_RECV_3";
|
||||
|
||||
case NET_PACKET_ONION_RECV_2:
|
||||
return "ONION_RECV_2";
|
||||
|
||||
case NET_PACKET_ONION_RECV_1:
|
||||
return "ONION_RECV_1";
|
||||
|
||||
case NET_PACKET_FORWARD_REQUEST:
|
||||
return "FORWARD_REQUEST";
|
||||
|
||||
case NET_PACKET_FORWARDING:
|
||||
return "FORWARDING";
|
||||
|
||||
case NET_PACKET_FORWARD_REPLY:
|
||||
return "FORWARD_REPLY";
|
||||
|
||||
case NET_PACKET_DATA_SEARCH_REQUEST:
|
||||
return "DATA_SEARCH_REQUEST";
|
||||
|
||||
case NET_PACKET_DATA_SEARCH_RESPONSE:
|
||||
return "DATA_SEARCH_RESPONSE";
|
||||
|
||||
case NET_PACKET_DATA_RETRIEVE_REQUEST:
|
||||
return "DATA_RETRIEVE_REQUEST";
|
||||
|
||||
case NET_PACKET_DATA_RETRIEVE_RESPONSE:
|
||||
return "DATA_RETRIEVE_RESPONSE";
|
||||
|
||||
case NET_PACKET_STORE_ANNOUNCE_REQUEST:
|
||||
return "STORE_ANNOUNCE_REQUEST";
|
||||
|
||||
case NET_PACKET_STORE_ANNOUNCE_RESPONSE:
|
||||
return "STORE_ANNOUNCE_RESPONSE";
|
||||
|
||||
case BOOTSTRAP_INFO_PACKET_ID:
|
||||
return "BOOTSTRAP_INFO";
|
||||
|
||||
case NET_PACKET_MAX:
|
||||
return "MAX";
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
non_null()
|
||||
static void loglogdata(const Logger *log, const char *message, const uint8_t *buffer,
|
||||
uint16_t buflen, const IP_Port *ip_port, long res)
|
||||
|
@ -663,21 +779,24 @@ static void loglogdata(const Logger *log, const char *message, const uint8_t *bu
|
|||
Ip_Ntoa ip_str;
|
||||
const int error = net_error();
|
||||
char *strerror = net_new_strerror(error);
|
||||
LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x",
|
||||
buffer[0], message, min_u16(buflen, 999), 'E',
|
||||
LOGGER_TRACE(log, "[%02x = %-20s] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x",
|
||||
buffer[0], net_packet_type_name((Net_Packet_Type)buffer[0]), message,
|
||||
min_u16(buflen, 999), 'E',
|
||||
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), error,
|
||||
strerror, data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]);
|
||||
net_kill_strerror(strerror);
|
||||
} else if ((res > 0) && ((size_t)res <= buflen)) {
|
||||
Ip_Ntoa ip_str;
|
||||
LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x",
|
||||
buffer[0], message, min_u16(res, 999), (size_t)res < buflen ? '<' : '=',
|
||||
LOGGER_TRACE(log, "[%02x = %-20s] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x",
|
||||
buffer[0], net_packet_type_name((Net_Packet_Type)buffer[0]), message,
|
||||
min_u16(res, 999), (size_t)res < buflen ? '<' : '=',
|
||||
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), 0, "OK",
|
||||
data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]);
|
||||
} else { /* empty or overwrite */
|
||||
Ip_Ntoa ip_str;
|
||||
LOGGER_TRACE(log, "[%2u] %s %lu%c%u %s:%u (%u: %s) | %08x%08x...%02x",
|
||||
buffer[0], message, res, res == 0 ? '!' : '>', buflen,
|
||||
LOGGER_TRACE(log, "[%02x = %-20s] %s %lu%c%u %s:%u (%u: %s) | %08x%08x...%02x",
|
||||
buffer[0], net_packet_type_name((Net_Packet_Type)buffer[0]), message,
|
||||
res, res == 0 ? '!' : '>', buflen,
|
||||
net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), 0, "OK",
|
||||
data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]);
|
||||
}
|
||||
|
@ -1628,7 +1747,7 @@ bool net_connect(const Logger *log, Socket sock, const IP_Port *ip_port)
|
|||
|
||||
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));
|
||||
(int)sock.sock, net_ip_ntoa(&ip_port->ip, &ip_str), ip_port->port);
|
||||
errno = 0;
|
||||
|
||||
if (connect(sock.sock, (struct sockaddr *)&addr, addrsize) == -1) {
|
||||
|
@ -1649,18 +1768,6 @@ bool net_connect(const Logger *log, Socket sock, const IP_Port *ip_port)
|
|||
|
||||
int32_t net_getipport(const char *node, IP_Port **res, int tox_type)
|
||||
{
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
if ((true)) {
|
||||
*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;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try parsing as IP address first.
|
||||
IP_Port parsed = {{{0}}};
|
||||
|
||||
|
@ -1676,6 +1783,18 @@ int32_t net_getipport(const char *node, IP_Port **res, int tox_type)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
if ((true)) {
|
||||
*res = (IP_Port *)calloc(1, sizeof(IP_Port));
|
||||
assert(*res != nullptr);
|
||||
IP_Port *ip_port = *res;
|
||||
ip_port->ip.ip.v4.uint32 = net_htonl(0x7F000003); // 127.0.0.3
|
||||
ip_port->ip.family = *make_tox_family(AF_INET);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// It's not an IP address, so now we try doing a DNS lookup.
|
||||
struct addrinfo *infos;
|
||||
const int ret = getaddrinfo(node, nullptr, nullptr, &infos);
|
||||
|
|
Loading…
Reference in New Issue
Block a user