diff options
Diffstat (limited to 'oss-fuzz/fuzzing')
-rw-r--r-- | oss-fuzz/fuzzing/Readme.md | 6 | ||||
-rw-r--r-- | oss-fuzz/fuzzing/datasource/datasource.hpp | 167 | ||||
-rw-r--r-- | oss-fuzz/fuzzing/datasource/id.hpp | 52 | ||||
-rw-r--r-- | oss-fuzz/fuzzing/exception.hpp | 44 | ||||
-rw-r--r-- | oss-fuzz/fuzzing/memory.hpp | 73 | ||||
-rw-r--r-- | oss-fuzz/fuzzing/types.hpp | 135 |
6 files changed, 477 insertions, 0 deletions
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 <fuzzing/exception.hpp> +#include <fuzzing/types.hpp> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <string> +#include <vector> + +namespace fuzzing { +namespace datasource { + +class Base +{ + protected: + virtual std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) = 0; + public: + Base(void) = default; + virtual ~Base(void) = default; + + template<class T> T Get(const uint64_t id = 0); + uint16_t GetChoice(const uint64_t id = 0); + std::vector<uint8_t> GetData(const uint64_t id, const size_t min = 0, const size_t max = 0); + template <class T> std::vector<T> 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<class T> 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<bool>(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<std::string>(const uint64_t id) +{ + auto data = GetData(id); + return std::string(data.data(), data.data() + data.size()); +} + +template <> std::vector<std::string> Base::Get<std::vector<std::string>>(const uint64_t id) +{ + std::vector<std::string> ret; + while ( true ) { + auto data = GetData(id); + ret.push_back( std::string(data.data(), data.data() + data.size()) ); + if ( Get<bool>(id) == false ) { + break; + } + } + return ret; +} + +uint16_t Base::GetChoice(const uint64_t id) +{ + return Get<uint16_t>(id); +} + +std::vector<uint8_t> Base::GetData(const uint64_t id, const size_t min, const size_t max) +{ + return get(min, max, id); +} + + +template <> types::String<> Base::Get<types::String<>>(const uint64_t id) { + const auto data = GetData(id); + types::String<> ret(data.data(), data.size()); + return ret; +} + +template <> types::Data<> Base::Get<types::Data<>>(const uint64_t id) { + const auto data = GetData(id); + types::Data<> ret(data.data(), data.size()); + return ret; +} + +template <class T> +std::vector<T> Base::GetVector(const uint64_t id) { + std::vector<T> ret; + + while ( Get<bool>(id) == true ) { + ret.push_back( Get<T>(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<uint8_t> 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<uint8_t> 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<uint8_t> 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 <stdio.h> +#include <stdint.h> +#include <utility> +#include <map> + +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<const char*, uint64_t> IDPair(const char* const str, const uint64_t value = val_64_const) noexcept { + return {str, ID(str, value)}; +} + +using IDMap = std::map<const char*, uint64_t>; + +} /* 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 <exception> +#include <string> + +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 <stdio.h> +#include <optional> + +#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 <class T> +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 <cstdint> +#include <cstdlib> +#include <cstring> +#include <fuzzing/memory.hpp> +#include <vector> +#include <string> + +namespace fuzzing { +namespace types { + +template <typename CoreType, bool NullTerminated, bool UseMSAN = false> +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<CoreType*>(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<class T> + 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 <bool UseMSAN = false> using String = Container<char, true, UseMSAN>; +template <bool UseMSAN = false> using Data = Container<uint8_t, false, UseMSAN>; + +} /* namespace types */ +} /* namespace fuzzing */ |