Squashed 'external/toxcore/c-toxcore/' content from commit 67badf69
git-subtree-dir: external/toxcore/c-toxcore git-subtree-split: 67badf69416a74e74f6d7eb51dd96f37282b8455
This commit is contained in:
61
testing/BUILD.bazel
Normal file
61
testing/BUILD.bazel
Normal file
@ -0,0 +1,61 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
|
||||
|
||||
package(features = ["layering_check"])
|
||||
|
||||
CIMPLE_FILES = [
|
||||
"//c-toxcore/toxav:cimple_files",
|
||||
"//c-toxcore/toxcore:cimple_files",
|
||||
"//c-toxcore/toxencryptsave:cimple_files",
|
||||
]
|
||||
|
||||
sh_test(
|
||||
name = "cimple_test",
|
||||
size = "small",
|
||||
srcs = ["//hs-tokstyle/tools:check-cimple"],
|
||||
args = ["$(locations %s)" % f for f in CIMPLE_FILES] + [
|
||||
"-Wno-boolean-return",
|
||||
"-Wno-callback-names",
|
||||
"-Wno-callgraph",
|
||||
"-Wno-enum-names",
|
||||
"-Wno-type-check",
|
||||
"+RTS",
|
||||
"-N3",
|
||||
"-RTS",
|
||||
],
|
||||
data = CIMPLE_FILES,
|
||||
tags = ["haskell"],
|
||||
)
|
||||
|
||||
sh_test(
|
||||
name = "cimplefmt_test",
|
||||
size = "small",
|
||||
srcs = ["//hs-cimple/tools:cimplefmt"],
|
||||
args = ["--reparse"] + ["$(locations %s)" % f for f in CIMPLE_FILES],
|
||||
data = CIMPLE_FILES,
|
||||
tags = ["haskell"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "misc_tools",
|
||||
testonly = 1,
|
||||
srcs = ["misc_tools.c"],
|
||||
hdrs = ["misc_tools.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
"//c-toxcore/toxcore:ccompat",
|
||||
"//c-toxcore/toxcore:tox",
|
||||
"@libsodium",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "Messenger_test",
|
||||
testonly = 1,
|
||||
srcs = ["Messenger_test.c"],
|
||||
deps = [
|
||||
":misc_tools",
|
||||
"//c-toxcore/toxcore:Messenger",
|
||||
"//c-toxcore/toxcore:ccompat",
|
||||
"//c-toxcore/toxcore:mono_time",
|
||||
],
|
||||
)
|
17
testing/CMakeLists.txt
Normal file
17
testing/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
# Helpful code for tests and other utilities
|
||||
set(misc_tools_SOURCES
|
||||
misc_tools.c
|
||||
misc_tools.h)
|
||||
add_library(misc_tools STATIC ${misc_tools_SOURCES})
|
||||
target_link_modules(misc_tools toxcore)
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# :: Test programs
|
||||
#
|
||||
################################################################################
|
||||
|
||||
if (BUILD_MISC_TESTS)
|
||||
add_executable(Messenger_test Messenger_test.c)
|
||||
target_link_modules(Messenger_test toxcore misc_tools)
|
||||
endif()
|
66
testing/Dockerfile
Normal file
66
testing/Dockerfile
Normal file
@ -0,0 +1,66 @@
|
||||
# based on https://github.com/AFLplusplus/AFLplusplus/blob/stable/Dockerfile
|
||||
|
||||
FROM ubuntu:20.04
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
ENV NO_ARCH_OPT 1
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||
automake \
|
||||
ninja-build \
|
||||
bison flex \
|
||||
build-essential \
|
||||
git \
|
||||
python3 python3-dev python3-setuptools python-is-python3 \
|
||||
libtool libtool-bin \
|
||||
libglib2.0-dev \
|
||||
wget vim jupp nano bash-completion less \
|
||||
apt-utils apt-transport-https ca-certificates gnupg dialog \
|
||||
libpixman-1-dev \
|
||||
gnuplot-nox \
|
||||
screen \
|
||||
cmake \
|
||||
parallel \
|
||||
libsodium-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" >> /etc/apt/sources.list && \
|
||||
wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
|
||||
RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main" >> /etc/apt/sources.list && \
|
||||
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F
|
||||
|
||||
RUN apt-get update && apt-get full-upgrade -y && \
|
||||
apt-get -y install --no-install-suggests --no-install-recommends \
|
||||
gcc-10 g++-10 gcc-10-plugin-dev gcc-10-multilib gcc-multilib gdb lcov \
|
||||
clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
|
||||
libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
|
||||
libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
|
||||
liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
|
||||
libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0
|
||||
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
|
||||
|
||||
ENV LLVM_CONFIG=llvm-config-12
|
||||
ENV AFL_SKIP_CPUFREQ=1
|
||||
ENV AFL_TRY_AFFINITY=1
|
||||
ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
|
||||
|
||||
RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov
|
||||
WORKDIR /afl-cov
|
||||
RUN make install
|
||||
|
||||
RUN git clone --depth=1 https://github.com/AFLplusplus/AFLplusplus /AFLplusplus
|
||||
WORKDIR /AFLplusplus
|
||||
RUN export CC=gcc-10 && export CXX=g++-10 && make install
|
||||
|
||||
RUN echo '. /etc/bash_completion' >> ~/.bashrc
|
||||
RUN echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc
|
||||
ENV IS_DOCKER="1"
|
||||
ENV CMAKE_GENERATOR=Ninja
|
34
testing/Makefile.inc
Normal file
34
testing/Makefile.inc
Normal file
@ -0,0 +1,34 @@
|
||||
if BUILD_TESTS
|
||||
TEST_LIB = misc_tools
|
||||
endif
|
||||
if BUILD_TESTING
|
||||
TEST_LIB = misc_tools
|
||||
endif
|
||||
|
||||
noinst_LTLIBRARIES += libmisc_tools.la
|
||||
libmisc_tools_la_SOURCES = ../testing/misc_tools.c ../testing/misc_tools.h
|
||||
|
||||
libmisc_tools_la_CFLAGS = $(LIBSODIUM_CFLAGS)
|
||||
|
||||
libmisc_tools_la_LIBADD = $(LIBSODIUM_LDFLAGS)
|
||||
|
||||
if BUILD_TESTING
|
||||
|
||||
noinst_PROGRAMS += Messenger_test
|
||||
|
||||
Messenger_test_SOURCES = \
|
||||
../testing/Messenger_test.c
|
||||
|
||||
Messenger_test_CFLAGS = $(LIBSODIUM_CFLAGS) \
|
||||
$(NACL_CFLAGS)
|
||||
|
||||
Messenger_test_LDADD = $(LIBSODIUM_LDFLAGS) \
|
||||
$(NACL_LDFLAGS) \
|
||||
libmisc_tools.la \
|
||||
libtoxcore.la \
|
||||
$(LIBSODIUM_LIBS) \
|
||||
$(NACL_OBJECTS) \
|
||||
$(NACL_LIBS) \
|
||||
$(WINSOCK2_LIBS)
|
||||
|
||||
endif
|
208
testing/Messenger_test.c
Normal file
208
testing/Messenger_test.c
Normal file
@ -0,0 +1,208 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/* Messenger test
|
||||
*
|
||||
* This program adds a friend and accepts all friend requests with the proper message.
|
||||
*
|
||||
* It tries sending a message to the added friend.
|
||||
*
|
||||
* If it receives a message from a friend it replies back.
|
||||
*
|
||||
*
|
||||
* This is how I compile it: gcc -O2 -Wall -D VANILLA_NACL -o test ../core/Lossless_UDP.c ../core/network.c ../core/net_crypto.c ../core/Messenger.c ../core/DHT.c ../nacl/build/${HOSTNAME%.*}/lib/amd64/{cpucycles.o,libnacl.a,randombytes.o} Messenger_test.c
|
||||
*
|
||||
*
|
||||
* Command line arguments are the ip, port and public_key of a node (for bootstrapping).
|
||||
*
|
||||
* EX: ./test 127.0.0.1 33445 CDCFD319CE3460824B33BE58FD86B8941C9585181D8FBD7C79C5721D7C2E9F7C
|
||||
*
|
||||
* Or the argument can be the path to the save file.
|
||||
*
|
||||
* EX: ./test Save.bak
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "../toxcore/Messenger.h"
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/mono_time.h"
|
||||
#include "misc_tools.h"
|
||||
|
||||
static void print_message(Messenger *m, uint32_t friendnumber, unsigned int type, const uint8_t *string, size_t length,
|
||||
void *userdata)
|
||||
{
|
||||
printf("Message with length %u received from %u: %s \n", (unsigned)length, friendnumber, string);
|
||||
m_send_message_generic(m, friendnumber, type, (const uint8_t *)"Test1", 6, nullptr);
|
||||
}
|
||||
|
||||
/* TODO(irungentoo): needed as print_request has to match the interface expected by
|
||||
* networking_requesthandler and so cannot take a Messenger * */
|
||||
static Messenger *m;
|
||||
|
||||
static void print_request(Messenger *m2, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||
{
|
||||
printf("Friend request received from: \n");
|
||||
printf("ClientID: ");
|
||||
uint32_t j;
|
||||
|
||||
for (j = 0; j < 32; j++) {
|
||||
if (public_key[j] < 16) {
|
||||
printf("0");
|
||||
}
|
||||
|
||||
printf("%hhX", public_key[j]);
|
||||
}
|
||||
|
||||
printf("\nOf length: %u with data: %s \n", (unsigned)length, data);
|
||||
|
||||
if (length != sizeof("Install Gentoo")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(data, "Install Gentoo", sizeof("Install Gentoo")) == 0)
|
||||
//if the request contained the message of peace the person is obviously a friend so we add him.
|
||||
{
|
||||
printf("Friend request accepted.\n");
|
||||
m_addfriend_norequest(m2, public_key);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* let user override default by cmdline */
|
||||
bool ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
|
||||
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
|
||||
|
||||
if (argvoffset < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* with optional --ipvx, now it can be 1-4 arguments... */
|
||||
if (argc != argvoffset + 4) {
|
||||
printf("Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node)\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Mono_Time *const mono_time = mono_time_new(nullptr, nullptr);
|
||||
|
||||
if (mono_time == nullptr) {
|
||||
fputs("Failed to allocate monotonic timer datastructure\n", stderr);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Messenger_Options options = {0};
|
||||
options.ipv6enabled = ipv6enabled;
|
||||
Messenger_Error err;
|
||||
m = new_messenger(mono_time, system_random(), system_network(), &options, &err);
|
||||
|
||||
if (!m) {
|
||||
fprintf(stderr, "Failed to allocate messenger datastructure: %d\n", err);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc == argvoffset + 4) {
|
||||
const long int port_conv = strtol(argv[argvoffset + 2], nullptr, 10);
|
||||
|
||||
if (port_conv <= 0 || port_conv > UINT16_MAX) {
|
||||
printf("Failed to convert \"%s\" into a valid port. Exiting...\n", argv[argvoffset + 2]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const uint16_t port = net_htons((uint16_t)port_conv);
|
||||
uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]);
|
||||
int res = dht_bootstrap_from_address(m->dht, argv[argvoffset + 1],
|
||||
ipv6enabled, port, bootstrap_key);
|
||||
free(bootstrap_key);
|
||||
|
||||
if (!res) {
|
||||
printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
m_callback_friendrequest(m, print_request);
|
||||
m_callback_friendmessage(m, print_message);
|
||||
|
||||
printf("OUR ID: ");
|
||||
uint32_t i;
|
||||
uint8_t address[FRIEND_ADDRESS_SIZE];
|
||||
getaddress(m, address);
|
||||
|
||||
for (i = 0; i < FRIEND_ADDRESS_SIZE; i++) {
|
||||
if (address[i] < 16) {
|
||||
printf("0");
|
||||
}
|
||||
|
||||
printf("%hhX", address[i]);
|
||||
}
|
||||
|
||||
setname(m, (const uint8_t *)"Anon", 5);
|
||||
|
||||
char temp_hex_id[128];
|
||||
printf("\nEnter the address of the friend you wish to add (38 bytes HEX format):\n");
|
||||
|
||||
if (!fgets(temp_hex_id, sizeof(temp_hex_id), stdin)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ((strlen(temp_hex_id) > 0) && (temp_hex_id[strlen(temp_hex_id) - 1] == '\n')) {
|
||||
temp_hex_id[strlen(temp_hex_id) - 1] = '\0';
|
||||
}
|
||||
|
||||
uint8_t *bin_id = hex_string_to_bin(temp_hex_id);
|
||||
const int num = m_addfriend(m, bin_id, (const uint8_t *)"Install Gentoo", sizeof("Install Gentoo"));
|
||||
free(bin_id);
|
||||
|
||||
perror("Initialization");
|
||||
|
||||
while (1) {
|
||||
mono_time_update(mono_time);
|
||||
|
||||
uint8_t name[128];
|
||||
const char *const filename = "Save.bak";
|
||||
getname(m, num, name);
|
||||
printf("%s\n", name);
|
||||
|
||||
m_send_message_generic(m, num, MESSAGE_NORMAL, (const uint8_t *)"Test", 5, nullptr);
|
||||
do_messenger(m, nullptr);
|
||||
c_sleep(30);
|
||||
FILE *file = fopen(filename, "wb");
|
||||
|
||||
if (file == nullptr) {
|
||||
printf("Failed to open file %s\n", filename);
|
||||
kill_messenger(m);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *buffer = (uint8_t *)malloc(messenger_size(m));
|
||||
|
||||
if (buffer == nullptr) {
|
||||
fputs("Failed to allocate memory\n", stderr);
|
||||
fclose(file);
|
||||
kill_messenger(m);
|
||||
return 1;
|
||||
}
|
||||
|
||||
messenger_save(m, buffer);
|
||||
const size_t write_result = fwrite(buffer, 1, messenger_size(m), file);
|
||||
|
||||
if (write_result < messenger_size(m)) {
|
||||
free(buffer);
|
||||
fclose(file);
|
||||
kill_messenger(m);
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
BIN
testing/afl_testdata/tox_saves/david.tox
Normal file
BIN
testing/afl_testdata/tox_saves/david.tox
Normal file
Binary file not shown.
7
testing/coverage_live.sh
Executable file
7
testing/coverage_live.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Move to repo root
|
||||
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 ../
|
36
testing/distill_corpus.sh
Executable file
36
testing/distill_corpus.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
|
||||
HARNESS_BIN="../_afl_build/bootstrap_fuzzer"
|
||||
COV_BIN="../_cov_build/bootstrap_fuzzer"
|
||||
# move to repo root
|
||||
cd ../
|
||||
|
||||
cd _afl_out/
|
||||
|
||||
# Perform corpus minimization
|
||||
mkdir -p corpus-cmin
|
||||
rm corpus-cmin/*
|
||||
|
||||
afl-cmin -i fuzz0/queue/ -o corpus-cmin/ -- "$HARNESS_BIN"
|
||||
|
||||
# Minimize each testcase
|
||||
mkdir -p corpus-tmin
|
||||
rm corpus-tmin/*
|
||||
|
||||
# afl-tmin is VERY slow
|
||||
# massive parallel bash piping for the rescue
|
||||
find corpus-cmin/ -maxdepth 1 -type f |
|
||||
parallel --bar --joblog ./parallel.log afl-tmin -i ./corpus-cmin/{/} -o ./corpus-tmin/{/} -- "$HARNESS_BIN"
|
||||
|
||||
# in case the tmin-process was aborted, just copy non-minimized files
|
||||
cp -n ./corpus-cmin/* ./corpus-tmin
|
||||
|
||||
# hack to let afl-cov run code coverage on our minimal corpus
|
||||
|
||||
rm -R corpus-cov
|
||||
mkdir -p corpus-cov/queue
|
||||
|
||||
cp corpus-tmin/* corpus-cov/queue
|
||||
|
||||
# Run code coverage only on minized corpus to save time
|
||||
afl-cov --cover-corpus -d ./corpus-cov --overwrite --coverage-cmd "$COV_BIN @@" --code-dir ../
|
101
testing/fuzzing/BUILD.bazel
Normal file
101
testing/fuzzing/BUILD.bazel
Normal file
@ -0,0 +1,101 @@
|
||||
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"])
|
||||
|
||||
cc_library(
|
||||
name = "fuzz_support",
|
||||
srcs = [
|
||||
"func_conversion.h",
|
||||
"fuzz_support.cc",
|
||||
],
|
||||
hdrs = ["fuzz_support.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [
|
||||
"//c-toxcore/toxcore:crypto_core",
|
||||
"//c-toxcore/toxcore:network",
|
||||
"//c-toxcore/toxcore:tox",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "fuzz_tox",
|
||||
hdrs = ["fuzz_tox.h"],
|
||||
visibility = ["//c-toxcore:__subpackages__"],
|
||||
deps = [":fuzz_support"],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "bootstrap_fuzz_test",
|
||||
srcs = ["bootstrap_harness.cc"],
|
||||
copts = ["-UNDEBUG"],
|
||||
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",
|
||||
],
|
||||
)
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "toxsave_fuzz_test",
|
||||
srcs = ["toxsave_harness.cc"],
|
||||
copts = ["-UNDEBUG"],
|
||||
corpus = ["//tools/toktok-fuzzer/corpus:toxsave_fuzzer"],
|
||||
deps = [
|
||||
":fuzz_support",
|
||||
"//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",
|
||||
],
|
||||
)
|
26
testing/fuzzing/CMakeLists.txt
Normal file
26
testing/fuzzing/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
||||
# For coverage tests
|
||||
target_compile_definitions(toxcore_static PUBLIC "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
|
||||
|
||||
# Override network and random functions
|
||||
add_library(fuzz_support func_conversion.h fuzz_support.cc fuzz_support.h)
|
||||
|
||||
set(LIBFUZZER_LINKER_FLAGS)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(LIBFUZZER_LINKER_FLAGS "-fsanitize=fuzzer")
|
||||
else()
|
||||
message(SEND_ERROR "Compiler must be Clang to build fuzz targets")
|
||||
endif()
|
||||
|
||||
# Fuzzes the toxsave API
|
||||
add_executable(toxsave_fuzzer toxsave_harness.cc)
|
||||
target_link_libraries(toxsave_fuzzer toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS})
|
||||
|
||||
# Fuzzes the bootstrap process
|
||||
add_executable(bootstrap_fuzzer bootstrap_harness.cc)
|
||||
target_link_libraries(bootstrap_fuzzer toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS})
|
||||
|
||||
add_executable(DHT_fuzz_test ../../toxcore/DHT_fuzz_test.cc)
|
||||
target_link_libraries(DHT_fuzz_test toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS})
|
||||
|
||||
add_executable(tox_events_fuzz_test ../../toxcore/tox_events_fuzz_test.cc)
|
||||
target_link_libraries(tox_events_fuzz_test toxcore_static fuzz_support ${LIBFUZZER_LINKER_FLAGS})
|
192
testing/fuzzing/bootstrap_harness.cc
Normal file
192
testing/fuzzing/bootstrap_harness.cc
Normal file
@ -0,0 +1,192 @@
|
||||
#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 {
|
||||
|
||||
void setup_callbacks(Tox_Dispatch *dispatch)
|
||||
{
|
||||
tox_events_callback_conference_connected(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Conference_Connected *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_conference_connected(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Conference_Connected *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_conference_invite(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Conference_Invite *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_conference_message(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Conference_Message *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_conference_peer_list_changed(dispatch,
|
||||
[](Tox *tox, const Tox_Event_Conference_Peer_List_Changed *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_conference_peer_name(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Conference_Peer_Name *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_conference_title(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Conference_Title *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_file_chunk_request(
|
||||
dispatch, [](Tox *tox, const Tox_Event_File_Chunk_Request *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_file_recv(
|
||||
dispatch, [](Tox *tox, const Tox_Event_File_Recv *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_file_recv_chunk(
|
||||
dispatch, [](Tox *tox, const Tox_Event_File_Recv_Chunk *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_file_recv_control(
|
||||
dispatch, [](Tox *tox, const Tox_Event_File_Recv_Control *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_connection_status(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Connection_Status *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_lossless_packet(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Lossless_Packet *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_lossy_packet(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Lossy_Packet *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_message(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Message *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_name(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Name *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_read_receipt(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Read_Receipt *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_request(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) {
|
||||
Tox_Err_Friend_Add err;
|
||||
tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err);
|
||||
assert(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY
|
||||
|| err == TOX_ERR_FRIEND_ADD_ALREADY_SENT
|
||||
|| err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM);
|
||||
});
|
||||
tox_events_callback_friend_status(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_status_message(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Status_Message *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_friend_typing(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Friend_Typing *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
tox_events_callback_self_connection_status(
|
||||
dispatch, [](Tox *tox, const Tox_Event_Self_Connection_Status *event, void *user_data) {
|
||||
assert(event == nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
void TestBootstrap(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_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.get(), TOX_PROXY_TYPE_NONE);
|
||||
} else if (proxy_type == 1) {
|
||||
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.get(), TOX_PROXY_TYPE_HTTP);
|
||||
tox_options_set_proxy_host(opts.get(), "127.0.0.1");
|
||||
tox_options_set_proxy_port(opts.get(), 8080);
|
||||
}
|
||||
|
||||
CONSUME1_OR_RETURN(const uint8_t tcp_relay_enabled, input);
|
||||
if (tcp_relay_enabled >= (UINT8_MAX / 2)) {
|
||||
tox_options_set_tcp_port(opts.get(), 33445);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
uint8_t pub_key[TOX_PUBLIC_KEY_SIZE] = {0};
|
||||
|
||||
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.2", 33446, pub_key, nullptr);
|
||||
assert(tcp_success);
|
||||
|
||||
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 += 200;
|
||||
}
|
||||
|
||||
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};
|
||||
TestBootstrap(input);
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
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.
|
||||
}
|
69
testing/fuzzing/func_conversion.h
Normal file
69
testing/fuzzing/func_conversion.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TESTING_FUZZING_FUNC_CONVERSION_H
|
||||
#define C_TOXCORE_TESTING_FUZZING_FUNC_CONVERSION_H
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename F, F f>
|
||||
struct func_conversion {
|
||||
private:
|
||||
template <typename R, typename... Args>
|
||||
using func_pointer = R (*)(Args...);
|
||||
|
||||
template <typename From>
|
||||
struct static_caster {
|
||||
From obj;
|
||||
|
||||
template <typename To>
|
||||
operator To() const
|
||||
{
|
||||
return static_cast<To>(obj);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename R, typename Arg, typename... Args>
|
||||
constexpr operator func_pointer<R, Arg, Args...>()
|
||||
{
|
||||
return [](Arg obj, auto... args) { return f(static_caster<Arg>{obj}, args...); };
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
struct make_funptr;
|
||||
|
||||
template <typename T, typename R, typename... Args>
|
||||
struct make_funptr<R (T::*)(Args...) const> {
|
||||
using type = R (*)(Args...);
|
||||
};
|
||||
|
||||
/** @brief Turn a memfunptr type into a plain funptr type.
|
||||
*
|
||||
* Not needed in C++20, because we can pass the lambda itself as template
|
||||
* argument, but in C++17, we need to do an early conversion.
|
||||
*/
|
||||
template <typename F>
|
||||
using make_funptr_t = typename make_funptr<F>::type;
|
||||
|
||||
}
|
||||
|
||||
/** @brief Turn a C++ lambda into a C function pointer with `void*` param.
|
||||
*
|
||||
* Takes a lambda function with any pointer type as first parameter and turns it
|
||||
* into a C function pointer with `void*` as the first parameter. Internally, it
|
||||
* `static_cast`s that `void*` to the lambda's parameter type, avoiding a bunch
|
||||
* of casts inside the lambdas.
|
||||
*
|
||||
* This works on any type `T` that can be `static_cast` to `U`, not just `void*`
|
||||
* to `U*`, but the common case for C callbacks is `void*`.
|
||||
*/
|
||||
template <typename F>
|
||||
static constexpr auto operator!(F f)
|
||||
{
|
||||
return detail::func_conversion<detail::make_funptr_t<decltype(&F::operator())>, f>{};
|
||||
}
|
||||
|
||||
#endif // C_TOXCORE_TESTING_FUZZING_FUNC_CONVERSION_H
|
368
testing/fuzzing/fuzz_support.cc
Normal file
368
testing/fuzzing/fuzz_support.cc
Normal file
@ -0,0 +1,368 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2021-2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#include "fuzz_support.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "../../toxcore/crypto_core.h"
|
||||
#include "../../toxcore/network.h"
|
||||
#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;
|
||||
};
|
||||
|
||||
System::~System() { }
|
||||
|
||||
static int recv_common(Fuzz_Data &input, uint8_t *buf, size_t buf_len)
|
||||
{
|
||||
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;
|
||||
|
||||
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));
|
||||
|
||||
std::copy(input.data, input.data + res, buf);
|
||||
input.data += res;
|
||||
input.size -= res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static constexpr Network_Funcs fuzz_network_funcs = {
|
||||
/* .close = */  { return 0; },
|
||||
/* .accept = */  { return 1337; },
|
||||
/* .bind = */  { return 0; },
|
||||
/* .listen = */  { return 0; },
|
||||
/* .recvbuf = */
|
||||
 {
|
||||
assert(sock == 42 || sock == 1337);
|
||||
const size_t count = random_u16(self->rng.get());
|
||||
return static_cast<int>(std::min(count, self->data.size));
|
||||
},
|
||||
/* .recv = */
|
||||
 {
|
||||
assert(sock == 42 || sock == 1337);
|
||||
// Receive data from the fuzzer.
|
||||
return recv_common(self->data, buf, len);
|
||||
},
|
||||
/* .recvfrom = */
|
||||
 {
|
||||
assert(sock == 42 || sock == 1337);
|
||||
|
||||
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 = 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 = */
|
||||
 {
|
||||
assert(sock == 42 || sock == 1337);
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .sendto = */
|
||||
 {
|
||||
assert(sock == 42 || sock == 1337);
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .socket = */  { return 42; },
|
||||
/* .socket_nonblock = */  { return 0; },
|
||||
/* .getsockopt = */
|
||||
 {
|
||||
std::memset(optval, 0, *optlen);
|
||||
return 0;
|
||||
},
|
||||
/* .setsockopt = */
|
||||
 {
|
||||
return 0;
|
||||
},
|
||||
};
|
||||
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
},
|
||||
/* .random_uniform = */
|
||||
 {
|
||||
uint32_t randnum = 0;
|
||||
if (upper_bound > 0) {
|
||||
self->rng->funcs->random_bytes(
|
||||
self, reinterpret_cast<uint8_t *>(&randnum), sizeof(randnum));
|
||||
randnum %= upper_bound;
|
||||
}
|
||||
return randnum;
|
||||
},
|
||||
};
|
||||
|
||||
Fuzz_System::Fuzz_System(Fuzz_Data &input)
|
||||
: 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 =  { return self->clock; };
|
||||
sys->mono_time_user_data = this;
|
||||
sys->ns = ns.get();
|
||||
sys->rng = rng.get();
|
||||
}
|
||||
|
||||
static constexpr Network_Funcs null_network_funcs = {
|
||||
/* .close = */  { return 0; },
|
||||
/* .accept = */  { return 1337; },
|
||||
/* .bind = */  { return 0; },
|
||||
/* .listen = */  { return 0; },
|
||||
/* .recvbuf = */  { return 0; },
|
||||
/* .recv = */
|
||||
 {
|
||||
// Always fail.
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
},
|
||||
/* .recvfrom = */
|
||||
 {
|
||||
// Always fail.
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
},
|
||||
/* .send = */
|
||||
 {
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .sendto = */
|
||||
 {
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .socket = */  { return 42; },
|
||||
/* .socket_nonblock = */  { return 0; },
|
||||
/* .getsockopt = */
|
||||
 {
|
||||
std::memset(optval, 0, *optlen);
|
||||
return 0;
|
||||
},
|
||||
/* .setsockopt = */
|
||||
 {
|
||||
return 0;
|
||||
},
|
||||
};
|
||||
|
||||
static uint64_t simple_rng(uint64_t &seed)
|
||||
{
|
||||
// https://nuclear.llnl.gov/CNP/rng/rngman/node4.html
|
||||
seed = 2862933555777941757LL * seed + 3037000493LL;
|
||||
return seed;
|
||||
}
|
||||
|
||||
static constexpr Random_Funcs null_random_funcs = {
|
||||
/* .random_bytes = */
|
||||
 {
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
bytes[i] = simple_rng(self->seed) & 0xff;
|
||||
}
|
||||
},
|
||||
/* .random_uniform = */
|
||||
 {
|
||||
return static_cast<uint32_t>(simple_rng(self->seed)) % upper_bound;
|
||||
},
|
||||
};
|
||||
|
||||
Null_System::Null_System()
|
||||
: 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 =  { return self->clock; };
|
||||
sys->mono_time_user_data = this;
|
||||
sys->ns = ns.get();
|
||||
sys->rng = rng.get();
|
||||
}
|
||||
|
||||
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 = */  { return 0; },
|
||||
/* .accept = */  { return 2; },
|
||||
/* .bind = */
|
||||
 {
|
||||
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 = */  { return 0; },
|
||||
/* .recvbuf = */  { return 0; },
|
||||
/* .recv = */
|
||||
 {
|
||||
// Always fail.
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
},
|
||||
/* .recvfrom = */
|
||||
 {
|
||||
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 = */
|
||||
 {
|
||||
// Always succeed.
|
||||
return static_cast<int>(len);
|
||||
},
|
||||
/* .sendto = */
|
||||
 {
|
||||
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 = */  { return 42; },
|
||||
/* .socket_nonblock = */  { return 0; },
|
||||
/* .getsockopt = */
|
||||
 {
|
||||
std::memset(optval, 0, *optlen);
|
||||
return 0;
|
||||
},
|
||||
/* .setsockopt = */
|
||||
 {
|
||||
return 0;
|
||||
},
|
||||
};
|
||||
|
||||
static constexpr Random_Funcs record_random_funcs = {
|
||||
/* .random_bytes = */
|
||||
 {
|
||||
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 =  { 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});
|
||||
}
|
230
testing/fuzzing/fuzz_support.h
Normal file
230
testing/fuzzing/fuzz_support.h
Normal file
@ -0,0 +1,230 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2021-2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
|
||||
#define C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "../../toxcore/tox.h"
|
||||
|
||||
struct Fuzz_Data {
|
||||
const uint8_t *data;
|
||||
std::size_t size;
|
||||
|
||||
Fuzz_Data(const uint8_t *input_data, std::size_t input_size)
|
||||
: data(input_data), size(input_size)
|
||||
{}
|
||||
|
||||
Fuzz_Data &operator=(const Fuzz_Data &rhs) = delete;
|
||||
Fuzz_Data(const Fuzz_Data &rhs) = delete;
|
||||
|
||||
uint8_t consume1()
|
||||
{
|
||||
const uint8_t val = data[0];
|
||||
++data;
|
||||
--size;
|
||||
return val;
|
||||
}
|
||||
|
||||
const uint8_t *consume(std::size_t count)
|
||||
{
|
||||
const uint8_t *val = data;
|
||||
data += count;
|
||||
size -= count;
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Consumes 1 byte of the fuzzer input or returns if no data available.
|
||||
*
|
||||
* This advances the fuzzer input data by 1 byte and consumes that byte in the
|
||||
* declaration.
|
||||
*
|
||||
* @example
|
||||
* @code
|
||||
* CONSUME1_OR_RETURN(const uint8_t one_byte, input);
|
||||
* @endcode
|
||||
*/
|
||||
#define CONSUME1_OR_RETURN(DECL, INPUT) \
|
||||
if (INPUT.size < 1) { \
|
||||
return; \
|
||||
} \
|
||||
DECL = INPUT.consume1()
|
||||
|
||||
/** @brief Consumes SIZE bytes of the fuzzer input or returns if not enough data available.
|
||||
*
|
||||
* This advances the fuzzer input data by SIZE byte and consumes those bytes in
|
||||
* the declaration. If less than SIZE bytes are available in the fuzzer input,
|
||||
* this macro returns from the enclosing function.
|
||||
*
|
||||
* @example
|
||||
* @code
|
||||
* CONSUME_OR_RETURN(const uint8_t *ten_bytes, input, 10);
|
||||
* @endcode
|
||||
*/
|
||||
#define CONSUME_OR_RETURN(DECL, INPUT, SIZE) \
|
||||
if (INPUT.size < SIZE) { \
|
||||
return; \
|
||||
} \
|
||||
DECL = INPUT.consume(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.
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
Fuzz_Data input{data, size};
|
||||
|
||||
CONSUME1_OR_RETURN(uint8_t selector, input);
|
||||
return fuzz_select_target(selector, input, std::forward<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 : System {
|
||||
Fuzz_Data &data;
|
||||
|
||||
explicit Fuzz_System(Fuzz_Data &input);
|
||||
};
|
||||
|
||||
/**
|
||||
* A Tox_System implementation that consumes no fuzzer input but still has a
|
||||
* working and deterministic RNG. Network receive functions always fail, send
|
||||
* always succeeds.
|
||||
*/
|
||||
struct Null_System : System {
|
||||
uint64_t seed = 4; // chosen by fair dice roll. guaranteed to be random.
|
||||
|
||||
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
|
95
testing/fuzzing/fuzz_tox.h
Normal file
95
testing/fuzzing/fuzz_tox.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2022 The TokTok team.
|
||||
*/
|
||||
|
||||
#ifndef C_TOXCORE_TESTING_FUZZING_FUZZ_TOX_H
|
||||
#define C_TOXCORE_TESTING_FUZZING_FUZZ_TOX_H
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include "../../toxcore/DHT.h"
|
||||
#include "../../toxcore/logger.h"
|
||||
#include "../../toxcore/network.h"
|
||||
#include "fuzz_support.h"
|
||||
|
||||
constexpr uint16_t SIZE_IP_PORT = SIZE_IP6 + sizeof(uint16_t);
|
||||
|
||||
template <typename T>
|
||||
using Ptr = std::unique_ptr<T, void (*)(T *)>;
|
||||
|
||||
/** @brief Construct any Tox resource using fuzzer input data.
|
||||
*
|
||||
* Constructs (or fails by returning) a valid object of type T and passes it to
|
||||
* a function specified on the rhs of `>>`. Takes care of cleaning up the
|
||||
* resource after the specified function returns.
|
||||
*
|
||||
* Some `with` instances require additional inputs such as the `Fuzz_Data`
|
||||
* reference or a logger.
|
||||
*/
|
||||
template <typename T>
|
||||
struct with;
|
||||
|
||||
/** @brief Construct a Logger without logging callback.
|
||||
*/
|
||||
template <>
|
||||
struct with<Logger> {
|
||||
template <typename F>
|
||||
void operator>>(F &&f)
|
||||
{
|
||||
Ptr<Logger> logger(logger_new(), logger_kill);
|
||||
assert(logger != nullptr);
|
||||
f(std::move(logger));
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Construct an IP_Port by unpacking fuzzer input with `unpack_ip_port`.
|
||||
*/
|
||||
template <>
|
||||
struct with<IP_Port> {
|
||||
Fuzz_Data &input_;
|
||||
|
||||
template <typename F>
|
||||
void operator>>(F &&f)
|
||||
{
|
||||
CONSUME_OR_RETURN(const uint8_t *ipp_packed, input_, SIZE_IP_PORT);
|
||||
IP_Port ipp;
|
||||
unpack_ip_port(&ipp, ipp_packed, SIZE_IP6, true);
|
||||
|
||||
f(ipp);
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Construct a Networking_Core object using the Network vtable passed.
|
||||
*
|
||||
* Use `with<Logger>{} >> with<Networking_Core>{input, ns} >> ...` to construct
|
||||
* a logger and pass it to the Networking_Core constructor function.
|
||||
*/
|
||||
template <>
|
||||
struct with<Networking_Core> {
|
||||
Fuzz_Data &input_;
|
||||
const Network *ns_;
|
||||
Ptr<Logger> logger_{nullptr, logger_kill};
|
||||
|
||||
friend with operator>>(with<Logger> f, with self)
|
||||
{
|
||||
f >> [&self](Ptr<Logger> logger) { self.logger_ = std::move(logger); };
|
||||
return self;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void operator>>(F &&f)
|
||||
{
|
||||
with<IP_Port>{input_} >> [&f, this](const IP_Port &ipp) {
|
||||
Ptr<Networking_Core> net(
|
||||
new_networking_ex(logger_.get(), ns_, &ipp.ip, ipp.port, ipp.port + 100, nullptr),
|
||||
kill_networking);
|
||||
if (net == nullptr) {
|
||||
return;
|
||||
}
|
||||
f(std::move(net));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
#endif // C_TOXCORE_TESTING_FUZZING_FUZZ_TOX_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.
|
||||
}
|
52
testing/fuzzing/toxsave_harness.cc
Normal file
52
testing/fuzzing/toxsave_harness.cc
Normal file
@ -0,0 +1,52 @@
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "../../toxcore/tox.h"
|
||||
#include "../../toxcore/tox_private.h"
|
||||
#include "fuzz_support.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void TestSaveDataLoading(Fuzz_Data &input)
|
||||
{
|
||||
Tox_Err_Options_New error_options;
|
||||
|
||||
struct Tox_Options *tox_options = tox_options_new(&error_options);
|
||||
|
||||
assert(tox_options != nullptr);
|
||||
assert(error_options == TOX_ERR_OPTIONS_NEW_OK);
|
||||
|
||||
const size_t savedata_size = input.size;
|
||||
CONSUME_OR_RETURN(const uint8_t *savedata, input, savedata_size);
|
||||
|
||||
Null_System sys;
|
||||
tox_options_set_operating_system(tox_options, sys.sys.get());
|
||||
|
||||
// pass test data to Tox
|
||||
tox_options_set_savedata_data(tox_options, savedata, savedata_size);
|
||||
tox_options_set_savedata_type(tox_options, TOX_SAVEDATA_TYPE_TOX_SAVE);
|
||||
|
||||
Tox *tox = tox_new(tox_options, nullptr);
|
||||
tox_options_free(tox_options);
|
||||
if (tox == nullptr) {
|
||||
// Tox save was invalid, we're finished here
|
||||
return;
|
||||
}
|
||||
|
||||
// verify that the file can be saved again
|
||||
std::vector<uint8_t> new_savedata(tox_get_savedata_size(tox));
|
||||
tox_get_savedata(tox, new_savedata.data());
|
||||
|
||||
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};
|
||||
TestSaveDataLoading(input);
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
208
testing/misc_tools.c
Normal file
208
testing/misc_tools.c
Normal file
@ -0,0 +1,208 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright © 2016-2018 The TokTok team.
|
||||
* Copyright © 2013 Tox project.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Miscellaneous functions and data structures for doing random things.
|
||||
*/
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
// For nanosleep().
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#endif
|
||||
|
||||
#include "misc_tools.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
#include <sodium.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
void c_sleep(uint32_t x)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
Sleep(x);
|
||||
#else
|
||||
struct timespec req;
|
||||
req.tv_sec = x / 1000;
|
||||
req.tv_nsec = (long)x % 1000 * 1000 * 1000;
|
||||
nanosleep(&req, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
// You are responsible for freeing the return value!
|
||||
uint8_t *hex_string_to_bin(const char *hex_string)
|
||||
{
|
||||
// byte is represented by exactly 2 hex digits, so length of binary string
|
||||
// is half of that of the hex one. only hex string with even length
|
||||
// valid. the more proper implementation would be to check if strlen(hex_string)
|
||||
// is odd and return error code if it is. we assume strlen is even. if it's not
|
||||
// then the last byte just won't be written in 'ret'.
|
||||
size_t i, len = strlen(hex_string) / 2;
|
||||
uint8_t *ret = (uint8_t *)malloc(len);
|
||||
const char *pos = hex_string;
|
||||
|
||||
if (ret == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i, pos += 2) {
|
||||
unsigned int val;
|
||||
sscanf(pos, "%02x", &val);
|
||||
ret[i] = val;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void to_hex(char *out, uint8_t *in, int size)
|
||||
{
|
||||
while (size--) {
|
||||
if (*in >> 4 < 0xA) {
|
||||
*out++ = '0' + (*in >> 4);
|
||||
} else {
|
||||
*out++ = 'A' + (*in >> 4) - 0xA;
|
||||
}
|
||||
|
||||
if ((*in & 0xf) < 0xA) {
|
||||
*out++ = '0' + (*in & 0xF);
|
||||
} else {
|
||||
*out++ = 'A' + (*in & 0xF) - 0xA;
|
||||
}
|
||||
|
||||
in++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reimplementation of strncasecmp() function from strings.h, as strings.h is
|
||||
* POSIX and not portable. Specifically it doesn't exist on MSVC.
|
||||
*/
|
||||
int tox_strncasecmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
while (n--) {
|
||||
int c1 = tolower(*(s1++));
|
||||
int c2 = tolower(*(s2++));
|
||||
|
||||
if (c1 == '\0' || c2 == '\0' || c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmdline_parsefor_ipv46(int argc, char **argv, bool *ipv6enabled)
|
||||
{
|
||||
int argvoffset = 0, argi;
|
||||
|
||||
for (argi = 1; argi < argc; argi++) {
|
||||
if (!tox_strncasecmp(argv[argi], "--ipv", 5)) {
|
||||
if (argv[argi][5] && !argv[argi][6]) {
|
||||
char c = argv[argi][5];
|
||||
|
||||
if (c == '4') {
|
||||
*ipv6enabled = false;
|
||||
} else if (c == '6') {
|
||||
*ipv6enabled = true;
|
||||
} else {
|
||||
printf("Invalid argument: %s. Try --ipv4 or --ipv6!\n", argv[argi]);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
printf("Invalid argument: %s. Try --ipv4 or --ipv6!\n", argv[argi]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argvoffset != argi - 1) {
|
||||
printf("Argument must come first: %s.\n", argv[argi]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
argvoffset++;
|
||||
}
|
||||
}
|
||||
|
||||
return argvoffset;
|
||||
}
|
||||
|
||||
|
||||
#ifndef VANILLA_NACL
|
||||
static const char *test_rng_name(void)
|
||||
{
|
||||
return "test_rng";
|
||||
}
|
||||
|
||||
static uint32_t rng_state;
|
||||
|
||||
static uint32_t test_rng_random(void)
|
||||
{
|
||||
rng_state = 2624534371 * rng_state + 1;
|
||||
return rng_state;
|
||||
}
|
||||
|
||||
static void test_rng_buf(void *const buf, const size_t size)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)buf;
|
||||
uint32_t r = 0;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if ((i % 4) == 0) {
|
||||
r = test_rng_random();
|
||||
}
|
||||
|
||||
*p = (r >> ((i % 4) * 8)) & 0xff;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t test_rng_uniform(const uint32_t upper_bound)
|
||||
{
|
||||
// XXX: Not uniform! But that's ok for testing purposes.
|
||||
return test_rng_random() % upper_bound;
|
||||
}
|
||||
|
||||
static void test_rng_stir(void) { }
|
||||
static int test_rng_close(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static randombytes_implementation test_rng = {
|
||||
test_rng_name,
|
||||
test_rng_random,
|
||||
test_rng_stir,
|
||||
test_rng_uniform,
|
||||
test_rng_buf,
|
||||
test_rng_close
|
||||
};
|
||||
|
||||
/* Simple insecure PRNG for testing purposes */
|
||||
int use_test_rng(uint32_t seed)
|
||||
{
|
||||
rng_state = seed;
|
||||
|
||||
return randombytes_set_implementation(&test_rng);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int use_test_rng(uint32_t seed)
|
||||
{
|
||||
assert(!"libsodium required for use_test_rng");
|
||||
}
|
||||
#endif
|
27
testing/misc_tools.h
Normal file
27
testing/misc_tools.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef C_TOXCORE_TESTING_MISC_TOOLS_H
|
||||
#define C_TOXCORE_TESTING_MISC_TOOLS_H
|
||||
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Amount of time in milliseconds to wait between tox_iterate calls.
|
||||
#define ITERATION_INTERVAL 200
|
||||
|
||||
void c_sleep(uint32_t x);
|
||||
|
||||
uint8_t *hex_string_to_bin(const char *hex_string);
|
||||
char *id_toa(const uint8_t *id);
|
||||
void to_hex(char *out, uint8_t *in, int size);
|
||||
int tox_strncasecmp(const char *s1, const char *s2, size_t n);
|
||||
int cmdline_parsefor_ipv46(int argc, char **argv, bool *ipv6enabled);
|
||||
|
||||
int use_test_rng(uint32_t seed);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
126
testing/run_afl.sh
Executable file
126
testing/run_afl.sh
Executable file
@ -0,0 +1,126 @@
|
||||
#!/bin/sh
|
||||
|
||||
COMMON_CMAKE_OPTIONS="-DCMAKE_C_COMPILER=afl-clang-lto -DCMAKE_CXX_COMPILER=afl-clang-lto++ -DBUILD_TOXAV=OFF -DENABLE_SHARED=NO -DBUILD_FUZZ_TESTS=ON -DDHT_BOOTSTRAP=OFF -DBOOTSTRAP_DAEMON=OFF"
|
||||
|
||||
# move to repo root
|
||||
cd ../
|
||||
|
||||
# build fuzzer target UBSAN
|
||||
mkdir -p _afl_build_ubsan
|
||||
cd _afl_build_ubsan
|
||||
|
||||
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
|
||||
|
||||
unset AFL_USE_UBSAN
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer target MSAN
|
||||
mkdir -p _afl_build_msan
|
||||
cd _afl_build_msan
|
||||
|
||||
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
|
||||
|
||||
unset AFL_USE_MSAN
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer target ASAN
|
||||
mkdir -p _afl_build_asan
|
||||
cd _afl_build_asan
|
||||
|
||||
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
|
||||
|
||||
unset AFL_USE_ASAN
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer 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
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer target with CmpLog
|
||||
mkdir -p _afl_build_cmplog
|
||||
cd _afl_build_cmplog
|
||||
|
||||
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
|
||||
|
||||
unset AFL_LLVM_CMPLOG
|
||||
|
||||
cd ..
|
||||
|
||||
# build fuzzer 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
|
||||
|
||||
# back to repo root
|
||||
cd ../
|
||||
|
||||
# Create fuzzer working directory
|
||||
|
||||
mkdir -p _afl_out
|
||||
|
||||
AFL_ARGS='-i testing/afl_testdata/tox_bootstraps/ -o _afl_out'
|
||||
|
||||
export AFL_IMPORT_FIRST=1
|
||||
export AFL_AUTORESUME=1
|
||||
|
||||
# faster startup
|
||||
export AFL_FAST_CAL=1
|
||||
|
||||
echo "connect to the fuzzers 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
|
||||
sleep 10s
|
||||
|
||||
# Secondary fuzzers
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz1 "$AFL_ARGS" -- ./_afl_build_msan/bootstrap_fuzzer
|
||||
sleep 1s
|
||||
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz2 "$AFL_ARGS" ./_afl_build_ubsan/bootstrap_fuzzer
|
||||
sleep 1s
|
||||
|
||||
screen -S fuzz -X screen afl-fuzz -S fuzz3 "$AFL_ARGS" ./_afl_build_asan/bootstrap_fuzzer
|
Reference in New Issue
Block a user