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.
This commit is contained in:
Erik de Castro Lopo
2019-11-17 16:08:07 +11:00
parent 888ea869a7
commit b19f3a6114
6 changed files with 477 additions and 0 deletions

View File

@@ -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.

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

135
oss-fuzz/fuzzing/types.hpp Normal file
View File

@@ -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 */