Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add automatic fuzz testing for c-toxcore #1720

Merged
merged 4 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .clusterfuzzlite/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# c-toxcore Clusterfuzzlite build environment

# We want to use the latest tools always
FROM gcr.io/oss-fuzz-base/base-builder:latest

RUN apt-get update && \
apt-get -y install --no-install-suggests --no-install-recommends \
cmake libtool autoconf automake pkg-config \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*


RUN git clone --depth 1 --branch 1.0.18 https://github.com/jedisct1/libsodium libsodium
sudden6 marked this conversation as resolved.
Show resolved Hide resolved
WORKDIR $SRC/libsodium
RUN ./autogen.sh && ./configure --enable-shared=no && make install

# Copy your project's source code.
COPY . $SRC/c-toxcore
# Working directory for build.sh.
WORKDIR $SRC/c-toxcore
# Copy build.sh into $SRC dir.
COPY ./.clusterfuzzlite/build.sh $SRC/
21 changes: 21 additions & 0 deletions .clusterfuzzlite/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash -eu

# out of tree build
cd "$WORK"

ls /usr/local/lib/

# Debug build for asserts
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER="$CC" \
-DCMAKE_CXX_COMPILER="$CXX" \
-DCMAKE_C_FLAGS="$CFLAGS" \
-DCMAKE_CXX_FLAGS="$CXXFLAGS" \
-DCMAKE_EXE_LINKER_FLAGS="$LIB_FUZZING_ENGINE" \
-DBUILD_TOXAV=OFF -DENABLE_SHARED=NO -DBUILD_FUZZ_TESTS=ON \
-DDHT_BOOTSTRAP=OFF -DBOOTSTRAP_DAEMON=OFF "$SRC"/c-toxcore

# build fuzzer target
cmake --build ./ --target bootstrap_fuzzer

# copy to output files
cp "$WORK"/bootstrap_fuzzer "$OUT"/
1 change: 1 addition & 0 deletions .hadolint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ ignored:
- DL3008
- DL3013
- DL3018
- DL3059
21 changes: 18 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,23 @@ if (BUILD_MISC_TESTS)
target_link_libraries(cracker OpenMP::OpenMP_C)
endif()
endif()
endif()

# Enabling this breaks all other tests and no network connections will be possible
option(BUILD_FUZZ_TESTS "Build fuzzing harnesses" OFF)
sudden6 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add BUILD_FUZZ_TESTS to INSTALL.md, it attempts to provide a comprehensive list of cmake options.

if (BUILD_FUZZ_TESTS)
# For coverage tests
target_compile_definitions(toxcore_static PUBLIC "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")

# Override network and random functions
add_library(fuzz_adapter testing/fuzzing/fuzz_adapter.c)

add_executable(afl_toxsave
testing/afl_toxsave.c)
target_link_modules(afl_toxsave toxcore)
# Fuzzes the toxsave API
add_executable(toxsave_fuzzer testing/fuzzing/toxsave_harness.cc)
target_link_libraries(toxsave_fuzzer toxcore_static fuzz_adapter -fsanitize=fuzzer)

# Fuzzes the bootstrap process
add_executable(bootstrap_fuzzer testing/fuzzing/bootstrap_harness.cc)
target_link_libraries(bootstrap_fuzzer toxcore_static fuzz_adapter -fsanitize=fuzzer)
endif()

4 changes: 4 additions & 0 deletions other/analysis/gen-file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ CPPFLAGS+=("-Iother")
CPPFLAGS+=("-Iother/bootstrap_daemon/src")
CPPFLAGS+=("-Iother/fun")
CPPFLAGS+=("-Itesting")
CPPFLAGS+=("-Itesting/fuzzing")
CPPFLAGS+=("-Itesting/groupchats")
CPPFLAGS+=("-Itoxcore")
CPPFLAGS+=("-Itoxav")
Expand Down Expand Up @@ -44,14 +45,17 @@ callmain() {

put auto_tests/check_compat.h

# Include all C and C++ code
FIND_QUERY="find . '-(' -name '*.c' -or -name '*.cc' '-)'"
# Excludes
FIND_QUERY="$FIND_QUERY -and -not -wholename './_build/*'"
FIND_QUERY="$FIND_QUERY -and -not -wholename './super_donators/*'"
FIND_QUERY="$FIND_QUERY -and -not -name amalgamation.cc"
FIND_QUERY="$FIND_QUERY -and -not -name av_test.c"
FIND_QUERY="$FIND_QUERY -and -not -name dht_test.c"
FIND_QUERY="$FIND_QUERY -and -not -name trace.cc"
FIND_QUERY="$FIND_QUERY -and -not -name version_test.c"
FIND_QUERY="$FIND_QUERY -and -not -wholename './testing/fuzzing/*'"

readarray -t FILES <<<"$(eval "$FIND_QUERY")"

Expand Down
2 changes: 1 addition & 1 deletion other/bootstrap_daemon/docker/tox-bootstrapd.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
c2d45e89278e21f452cce2589299648bb94c38d75b0e974fb4f1c012182543af /usr/local/bin/tox-bootstrapd
bf2b6ce150f5dc3ed95e8636dd025a13015c98bbf922b7602969560d310045f7 /usr/local/bin/tox-bootstrapd
8 changes: 0 additions & 8 deletions testing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,3 @@ cc_binary(
"//c-toxcore/toxcore",
],
)

cc_binary(
name = "afl_toxsave",
srcs = ["afl_toxsave.c"],
deps = [
"//c-toxcore/toxcore",
],
)
67 changes: 67 additions & 0 deletions testing/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# 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 \
ninja-build\
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ninja-build appears twice.

&& rm -rf /var/lib/apt/lists/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add && apt-get clean before the rm -rf part. I think the downloaded .debs aren't stored in lists (but I might be wrong).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


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
56 changes: 0 additions & 56 deletions testing/afl_toxsave.c

This file was deleted.

7 changes: 7 additions & 0 deletions testing/coverage_live.sh
Original file line number Diff line number Diff line change
@@ -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 changes: 36 additions & 0 deletions testing/distill_corpus.sh
Original file line number Diff line number Diff line change
@@ -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 ../
33 changes: 33 additions & 0 deletions testing/fuzzing/bootstrap_harness.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <cassert>
#include <cstring>

#include "../../toxcore/tox.h"
#include "fuzz_adapter.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
network_adapter_init(data, size);

Tox_Err_New error_new;
Tox *tox = tox_new(NULL, &error_new);

assert(tox != nullptr);
assert(error_new == TOX_ERR_NEW_OK);

uint8_t pub_key[TOX_PUBLIC_KEY_SIZE] = {0};

bool success = tox_bootstrap(tox, "127.0.0.1", 12345, pub_key, nullptr);
assert(success);

/*
* The iteration count here is a magic value in the literal sense, too small
* and coverage will be bad, too big and fuzzing will not be efficient.
* NOTE: This should be fine tuned after gathering some experience.
*/

for (uint32_t i = 0; i < 100; ++i) {
tox_iterate(tox, nullptr);
}

tox_kill(tox);
return 0; // Non-zero return values are reserved for future use.
}
Loading