From b19f3a6114c8d6d98905c3ae8ae51eda84680918 Mon Sep 17 00:00:00 2001 From: Erik de Castro Lopo Date: Sun, 17 Nov 2019 16:08:07 +1100 Subject: oss-fuzz: Add fuzzing headers These includes header files were taken from: https://github.com/guidovranken/fuzzing-headers.git with some minor changes required to make them compile cleanly with the extra compiler warning flags used by the FLAC build system. --- oss-fuzz/fuzzing/Readme.md | 6 ++ oss-fuzz/fuzzing/datasource/datasource.hpp | 167 +++++++++++++++++++++++++++++ oss-fuzz/fuzzing/datasource/id.hpp | 52 +++++++++ oss-fuzz/fuzzing/exception.hpp | 44 ++++++++ oss-fuzz/fuzzing/memory.hpp | 73 +++++++++++++ oss-fuzz/fuzzing/types.hpp | 135 +++++++++++++++++++++++ 6 files changed, 477 insertions(+) create mode 100644 oss-fuzz/fuzzing/Readme.md create mode 100644 oss-fuzz/fuzzing/datasource/datasource.hpp create mode 100644 oss-fuzz/fuzzing/datasource/id.hpp create mode 100644 oss-fuzz/fuzzing/exception.hpp create mode 100644 oss-fuzz/fuzzing/memory.hpp create mode 100644 oss-fuzz/fuzzing/types.hpp diff --git a/oss-fuzz/fuzzing/Readme.md b/oss-fuzz/fuzzing/Readme.md new file mode 100644 index 00000000..d2fbd687 --- /dev/null +++ b/oss-fuzz/fuzzing/Readme.md @@ -0,0 +1,6 @@ +The header files in this directory and below were taken from: + + https://github.com/guidovranken/fuzzing-headers.git + +Some minor modifications were made to make them build with the default C++ +warning flags. diff --git a/oss-fuzz/fuzzing/datasource/datasource.hpp b/oss-fuzz/fuzzing/datasource/datasource.hpp new file mode 100644 index 00000000..e0699d3e --- /dev/null +++ b/oss-fuzz/fuzzing/datasource/datasource.hpp @@ -0,0 +1,167 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fuzzing { +namespace datasource { + +class Base +{ + protected: + virtual std::vector get(const size_t min, const size_t max, const uint64_t id = 0) = 0; + public: + Base(void) = default; + virtual ~Base(void) = default; + + template T Get(const uint64_t id = 0); + uint16_t GetChoice(const uint64_t id = 0); + std::vector GetData(const uint64_t id, const size_t min = 0, const size_t max = 0); + template std::vector GetVector(const uint64_t id = 0); + + class OutOfData : public fuzzing::exception::FlowException { + public: + OutOfData() = default; + }; + + class DeserializationFailure : public fuzzing::exception::FlowException { + public: + DeserializationFailure() = default; + }; +}; + +#ifndef FUZZING_HEADERS_NO_IMPL +template T Base::Get(const uint64_t id) +{ + T ret; + const auto v = get(sizeof(ret), sizeof(ret), id); + memcpy(&ret, v.data(), sizeof(ret)); + return ret; +} + +template <> bool Base::Get(const uint64_t id) +{ + uint8_t ret; + const auto v = get(sizeof(ret), sizeof(ret), id); + memcpy(&ret, v.data(), sizeof(ret)); + return (ret % 2) ? true : false; +} + +template <> std::string Base::Get(const uint64_t id) +{ + auto data = GetData(id); + return std::string(data.data(), data.data() + data.size()); +} + +template <> std::vector Base::Get>(const uint64_t id) +{ + std::vector ret; + while ( true ) { + auto data = GetData(id); + ret.push_back( std::string(data.data(), data.data() + data.size()) ); + if ( Get(id) == false ) { + break; + } + } + return ret; +} + +uint16_t Base::GetChoice(const uint64_t id) +{ + return Get(id); +} + +std::vector Base::GetData(const uint64_t id, const size_t min, const size_t max) +{ + return get(min, max, id); +} + + +template <> types::String<> Base::Get>(const uint64_t id) { + const auto data = GetData(id); + types::String<> ret(data.data(), data.size()); + return ret; +} + +template <> types::Data<> Base::Get>(const uint64_t id) { + const auto data = GetData(id); + types::Data<> ret(data.data(), data.size()); + return ret; +} + +template +std::vector Base::GetVector(const uint64_t id) { + std::vector ret; + + while ( Get(id) == true ) { + ret.push_back( Get(id) ); + } + + return ret; +} +#endif + +class Datasource : public Base +{ + private: + const uint8_t* data; + const size_t size; + size_t idx; + size_t left; + std::vector get(const size_t min, const size_t max, const uint64_t id = 0) override; + + // Make copy constructor and assignment opertator private. + Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {} + Datasource& operator=(const Datasource &) { return *this; } + public: + Datasource(const uint8_t* _data, const size_t _size); +}; + +#ifndef FUZZING_HEADERS_NO_IMPL +Datasource::Datasource(const uint8_t* _data, const size_t _size) : + Base(), data(_data), size(_size), idx(0), left(size) +{ +} + +std::vector Datasource::get(const size_t min, const size_t max, const uint64_t id) { + (void)id; + + uint32_t getSize; + if ( left < sizeof(getSize) ) { + throw OutOfData(); + } + memcpy(&getSize, data + idx, sizeof(getSize)); + idx += sizeof(getSize); + left -= sizeof(getSize); + + if ( getSize < min ) { + getSize = min; + } + if ( max && getSize > max ) { + getSize = max; + } + + if ( left < getSize ) { + throw OutOfData(); + } + + std::vector ret(getSize); + + if ( getSize > 0 ) { + memcpy(ret.data(), data + idx, getSize); + } + idx += getSize; + left -= getSize; + + return ret; +} +#endif + +} /* namespace datasource */ +} /* namespace fuzzing */ diff --git a/oss-fuzz/fuzzing/datasource/id.hpp b/oss-fuzz/fuzzing/datasource/id.hpp new file mode 100644 index 00000000..3ba38d71 --- /dev/null +++ b/oss-fuzz/fuzzing/datasource/id.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include + +namespace fuzzing { +namespace datasource { + +/* From: https://gist.github.com/underscorediscovery/81308642d0325fd386237cfa3b44785c */ +inline uint64_t hash_64_fnv1a(const void* key, const uint64_t len) { + + const char* data = (char*)key; + uint64_t hash = 0xcbf29ce484222325; + uint64_t prime = 0x100000001b3; + + for(uint64_t i = 0; i < len; ++i) { + uint8_t value = data[i]; + hash = hash ^ value; + hash *= prime; + } + + return hash; + +} //hash_64_fnv1a + +// FNV1a c++11 constexpr compile time hash functions, 32 and 64 bit +// str should be a null terminated string literal, value should be left out +// e.g hash_32_fnv1a_const("example") +// code license: public domain or equivalent +// post: https://notes.underscorediscovery.com/constexpr-fnv1a/ + +constexpr uint32_t val_32_const = 0x811c9dc5; +constexpr uint32_t prime_32_const = 0x1000193; +constexpr uint64_t val_64_const = 0xcbf29ce484222325; +constexpr uint64_t prime_64_const = 0x100000001b3; + + +inline constexpr uint64_t ID(const char* const str, const uint64_t value = val_64_const) noexcept { + auto ret = (str[0] == '\0') ? value : ID(&str[1], (value ^ uint64_t(str[0])) * prime_64_const); + return ret; +} + +inline constexpr std::pair IDPair(const char* const str, const uint64_t value = val_64_const) noexcept { + return {str, ID(str, value)}; +} + +using IDMap = std::map; + +} /* namespace datasource */ +} /* namespace fuzzing */ diff --git a/oss-fuzz/fuzzing/exception.hpp b/oss-fuzz/fuzzing/exception.hpp new file mode 100644 index 00000000..55c360de --- /dev/null +++ b/oss-fuzz/fuzzing/exception.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +namespace fuzzing { +namespace exception { + +class ExceptionBase : public std::exception { + public: + ExceptionBase(void) = default; + /* typeid(T).name */ +}; + +/* Recoverable exception */ +class FlowException : public ExceptionBase { + public: + FlowException(void) : ExceptionBase() { } +}; + +/* Error in this library, should never happen */ +class LogicException : public ExceptionBase { + private: + std::string reason; + public: + LogicException(const std::string r) : ExceptionBase(), reason(r) { } + virtual const char* what(void) const throw() { + return reason.c_str(); + } +}; + +/* Error in target application */ +class TargetException : public ExceptionBase { + private: + std::string reason; + public: + TargetException(const std::string r) : ExceptionBase(), reason(r) { } + virtual const char* what(void) const throw() { + return reason.c_str(); + } +}; + +} /* namespace exception */ +} /* namespace fuzzing */ diff --git a/oss-fuzz/fuzzing/memory.hpp b/oss-fuzz/fuzzing/memory.hpp new file mode 100644 index 00000000..804e23b4 --- /dev/null +++ b/oss-fuzz/fuzzing/memory.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +#ifndef ASAN +#define ASAN 0 +#endif + +#ifndef MSAN +#define MSAN 0 +#endif + +namespace fuzzing { +namespace memory { + +#ifndef FUZZING_HEADERS_NO_IMPL +#if ASAN == 1 +extern "C" void *__asan_region_is_poisoned(const void *beg, size_t size); +#endif + +#if MSAN == 1 +extern "C" void __msan_check_mem_is_initialized(const volatile void *x, size_t size); +#endif + +void memory_test_asan(const void* data, const size_t size) +{ + (void)data; + (void)size; + +#if ASAN == 1 + if ( __asan_region_is_poisoned(data, size) != NULL ) { + abort(); + } +#endif +} + +void memory_test_msan(const void* data, const size_t size) +{ + (void)data; + (void)size; + +#if MSAN == 1 + __msan_check_mem_is_initialized(data, size); +#endif +} + +void memory_test(const void* data, const size_t size) +{ + memory_test_asan(data, size); + memory_test_msan(data, size); +} + +template +void memory_test(const T& t) +{ + (void)t; +} + +template <> +void memory_test(const std::string& s) +{ + (void)s; + +#if MSAN == 1 + memory_test(s.data(), s.size()); +#endif +} + +#endif + +} /* namespace memory */ +} /* namespace fuzzing */ diff --git a/oss-fuzz/fuzzing/types.hpp b/oss-fuzz/fuzzing/types.hpp new file mode 100644 index 00000000..f2b56fc3 --- /dev/null +++ b/oss-fuzz/fuzzing/types.hpp @@ -0,0 +1,135 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace fuzzing { +namespace types { + +template +class Container { + private: + CoreType* InvalidAddress = (CoreType*)0x12; + + CoreType* _data = InvalidAddress; + size_t _size = 0; + +#ifndef FUZZING_HEADERS_NO_IMPL + void copy(const void* data, size_t size) { + if ( size > 0 ) { + std::memcpy(_data, data, size); + } + } + + void allocate(size_t size) { + if ( size > 0 ) { + _data = static_cast(malloc(size * sizeof(CoreType))); + } else { + _data = InvalidAddress; + } + }; + + void allocate_and_copy(const void* data, size_t size) { + allocate(size); + copy(data, size); + } + + void allocate_plus_1_and_copy(const void* data, size_t size) { + allocate(size+1); + copy(data, size); + } + + void access_hook(void) const { + if ( UseMSAN == true ) { + memory::memory_test_msan(_data, _size); + } + } + + void free(void) { + access_hook(); + + if ( _data != InvalidAddress ) { + std::free(_data); + _data = InvalidAddress; + _size = 0; + } + } + +#endif + + public: +#ifndef FUZZING_HEADERS_NO_IMPL + CoreType* data(void) { + access_hook(); + return _data; + } + + size_t size(void) const { + access_hook(); + return _size; + } +#endif + + Container(void) +#ifndef FUZZING_HEADERS_NO_IMPL + = default +#endif + ; + + Container(const void* data, const size_t size) +#ifndef FUZZING_HEADERS_NO_IMPL + { + if ( NullTerminated == false ) { + allocate_and_copy(data, size); + } else { + allocate_plus_1_and_copy(data, size); + _data[size] = 0; + } + + access_hook(); + } +#endif + ; + + template + Container(const T& t) +#ifndef FUZZING_HEADERS_NO_IMPL + { + Container(t.data(), t.size()); + } +#endif + ; + + ~Container(void) +#ifndef FUZZING_HEADERS_NO_IMPL + { + this->free(); + } +#endif + ; + + + + // The copy constructor was not originally explicitly supplied + // so it must have been incorrectly just copying the pointers. + Container(const Container &c) { + InvalidAddress = c.InvalidAddress; + allocate_and_copy(c._data, c._size); + } + + Container& operator=(Container &c) { + InvalidAddress = c.InvalidAddress; + allocate_and_copy(c._data, c._size); + } + +}; + +template using String = Container; +template using Data = Container; + +} /* namespace types */ +} /* namespace fuzzing */ -- cgit v1.2.1