Skip to content

Commit

Permalink
Buffer parser fuzzing (#2496)
Browse files Browse the repository at this point in the history
* Buffer parser fuzzing

* add clang-6 with libfuzzer base Dockerfile

Co-authored-by: Russel Waters <vaelstrom@gmail.com>
  • Loading branch information
cryptocode and argakiig committed Jan 28, 2020
1 parent a752deb commit d41d4c5
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 0 deletions.
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ set (NANO_ROCKSDB OFF CACHE BOOL "")
set (NANO_POW_SERVER OFF CACHE BOOL "")
set (NANO_WARN_TO_ERR OFF CACHE BOOL "")
set (NANO_TIMED_LOCKS 0 CACHE STRING "")
set (NANO_FUZZER_TEST OFF CACHE BOOL "")

option (NANO_STACKTRACE_BACKTRACE "Use BOOST_STACKTRACE_USE_BACKTRACE in stacktraces, for POSIX" OFF)
if (NANO_STACKTRACE_BACKTRACE)
Expand Down Expand Up @@ -110,6 +111,11 @@ else ()
add_definitions(-DED25519_NO_INLINE_ASM)
endif()

if (NANO_FUZZER_TEST)
add_compile_options (-fsanitize=fuzzer-no-link -fno-omit-frame-pointer)
add_definitions (-DNANO_FUZZER_TEST)
endif ()

if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86(_64)?)$")
if (NANO_SIMD_OPTIMIZATIONS OR RAIBLOCKS_SIMD_OPTIMIZATIONS OR ENABLE_AVX2)
add_compile_options(-msse4)
Expand Down Expand Up @@ -175,6 +181,9 @@ else ()
set (PLATFORM_LINK_FLAGS "${PLATFORM_LINK_FLAGS} -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/tsan_clang_blacklist")
endif()
endif()
if (NANO_FUZZER_TEST)
set (PLATFORM_LINK_FLAGS "${PLATFORM_LINK_FLAGS} -fsanitize=fuzzer-no-link")
endif ()
endif ()

SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINK_FLAGS}" )
Expand Down Expand Up @@ -352,6 +361,14 @@ add_subdirectory(nano/nano_node)
add_subdirectory(nano/rpc)
add_subdirectory(nano/nano_rpc)

if (NANO_FUZZER_TEST)
if (NOT WIN32)
add_subdirectory (nano/fuzzer_test)
else ()
message (WARNING "Fuzzing is not supported on Windows")
endif ()
endif ()

if (NANO_TEST OR RAIBLOCKS_TEST)
if(WIN32)
if(MSVC_VERSION)
Expand Down
22 changes: 22 additions & 0 deletions docker/ci/Dockerfile-clang-6
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM nanocurrency/nano-env:base

RUN apt-get update && apt-get install -yqq software-properties-common && \
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \
apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-6.0 main" && \
apt-get update -qq && apt-get install -yqq \
clang-6.0 lldb-6.0 libfuzzer-6.0-dev git

ADD util/build_prep/fetch_rocksdb.sh fetch_rocksdb.sh
RUN ./fetch_rocksdb.sh

ENV CXX=/usr/bin/clang++
ENV CC=/usr/bin/clang
RUN ln -s /usr/bin/clang-6.0 /usr/bin/clang
RUN ln -s /usr/bin/clang++-6.0 /usr/bin/clang++
RUN update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100
RUN update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100
ENV BOOST_ROOT=/tmp/boost

ADD util/build_prep/bootstrap_boost.sh bootstrap_boost.sh

RUN ./bootstrap_boost.sh -m -c -B 1.70
3 changes: 3 additions & 0 deletions nano/fuzzer_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_executable(fuzz_buffer fuzz_buffer.cpp)
target_compile_options(fuzz_buffer PUBLIC -fsanitize=fuzzer)
target_link_libraries(fuzz_buffer PRIVATE -fsanitize=fuzzer node)
75 changes: 75 additions & 0 deletions nano/fuzzer_test/fuzz_buffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <nano/core_test/testutil.hpp>
#include <nano/node/common.hpp>
#include <nano/node/testing.hpp>

#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <iostream>

namespace nano
{
void force_nano_test_network ();
}
namespace
{
std::shared_ptr<nano::system> system0;
std::shared_ptr<nano::node> node0;

class fuzz_visitor : public nano::message_visitor
{
public:
virtual void keepalive (nano::keepalive const &) override
{
}
virtual void publish (nano::publish const &) override
{
}
virtual void confirm_req (nano::confirm_req const &) override
{
}
virtual void confirm_ack (nano::confirm_ack const &) override
{
}
virtual void bulk_pull (nano::bulk_pull const &) override
{
}
virtual void bulk_pull_account (nano::bulk_pull_account const &) override
{
}
virtual void bulk_push (nano::bulk_push const &) override
{
}
virtual void frontier_req (nano::frontier_req const &) override
{
}
virtual void node_id_handshake (nano::node_id_handshake const &) override
{
}
};
}

/** Fuzz live message parsing. This covers parsing and block/vote uniquing. */
void fuzz_message_parser (const uint8_t * Data, size_t Size)
{
static bool initialized = false;
if (!initialized)
{
nano::force_nano_test_network ();
initialized = true;
system0 = std::make_shared<nano::system> (1);
node0 = system0->nodes[0];
}

fuzz_visitor visitor;
nano::message_parser parser (node0->block_uniquer, node0->vote_uniquer, visitor, node0->work);
parser.deserialize_buffer (Data, Size);
}

/** Fuzzer entry point */
extern "C" int LLVMFuzzerTestOneInput (const uint8_t * Data, size_t Size)
{
fuzz_message_parser (Data, Size);
return 0;
}
2 changes: 2 additions & 0 deletions nano/lib/blocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,9 @@ std::shared_ptr<nano::block> nano::deserialize_block (nano::stream & stream_a, n
break;
}
default:
#ifndef NANO_FUZZER_TEST
assert (false);
#endif
break;
}
if (uniquer_a != nullptr)
Expand Down
13 changes: 13 additions & 0 deletions nano/lib/work.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ bool nano::work_validate (nano::block const & block_a, uint64_t * difficulty_a)
return work_validate (block_a.root (), block_a.block_work (), difficulty_a);
}

#ifndef NANO_FUZZER_TEST
uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
{
uint64_t result;
Expand All @@ -32,6 +33,18 @@ uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
blake2b_final (&hash, reinterpret_cast<uint8_t *> (&result), sizeof (result));
return result;
}
#else
uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
{
static nano::network_constants network_constants;
if (!network_constants.is_test_network ())
{
assert (false);
std::exit (1);
}
return network_constants.publish_threshold + 1;
}
#endif

nano::work_pool::work_pool (unsigned max_threads_a, std::chrono::nanoseconds pow_rate_limiter_a, std::function<boost::optional<uint64_t> (nano::root const &, uint64_t, std::atomic<int> &)> opencl_a) :
ticket (0),
Expand Down

0 comments on commit d41d4c5

Please sign in to comment.