2019-05-03 00:29:04 +02:00
|
|
|
//
|
|
|
|
// fuzzing_directed.h
|
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
//
|
|
|
|
// The directed fuzzing definitions header. Requires C++0x11 support
|
|
|
|
// due to usage of variadic templates.
|
|
|
|
//
|
|
|
|
#ifndef __FUZZING_DIRECTED_H__
|
|
|
|
#define __FUZZING_DIRECTED_H__
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
#pragma warning(push)
|
2019-06-11 22:27:09 +02:00
|
|
|
#pragma warning(disable : 4242) // Standard random library contains C4242 warning about conversion from unsigned int to unsigned short.
|
2019-05-03 00:29:04 +02:00
|
|
|
#include <random>
|
|
|
|
#pragma warning(pop)
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <limits>
|
2020-07-01 20:00:24 +02:00
|
|
|
#include <cassert>
|
2019-05-03 00:29:04 +02:00
|
|
|
#include <strsafe.h>
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
#pragma warning(disable : 4505)
|
2019-05-21 19:32:43 +02:00
|
|
|
#include "memallocator.h"
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
#ifndef __FUZZING_ALLOCATOR
|
2019-05-21 19:32:43 +02:00
|
|
|
#define __FUZZING_ALLOCATOR fuzz::CFuzzCRTAllocator
|
2019-05-03 00:29:04 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace variadic
|
|
|
|
{
|
2019-06-11 22:27:09 +02:00
|
|
|
template<int... Is>
|
|
|
|
struct index
|
|
|
|
{
|
|
|
|
};
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
template<int N, int... Is>
|
|
|
|
struct gen_seq : gen_seq<N - 1, N - 1, Is...>
|
|
|
|
{
|
|
|
|
};
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
template<int... Is>
|
|
|
|
struct gen_seq<0, Is...> : index<Is...>
|
|
|
|
{
|
|
|
|
};
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace fuzz
|
|
|
|
{
|
2019-06-11 22:27:09 +02:00
|
|
|
// Fuzz traits change inherent behavior of the CFuzzType class
|
2019-05-03 00:29:04 +02:00
|
|
|
// (and associated derived classes). This is a bit-flag such that
|
|
|
|
// multiple traits can be applied as needed.
|
|
|
|
enum _FuzzTraits : unsigned int
|
|
|
|
{
|
|
|
|
// Default behavior is to not throw exceptions
|
|
|
|
TRAIT_DEFAULT = 0x0,
|
|
|
|
|
|
|
|
// In the event that the fuzz map percentages add up to more than
|
|
|
|
// 100% during constructor initialization, an exception of type
|
|
|
|
// CFuzzRangeException is thrown.
|
|
|
|
TRAIT_THROW_ON_INIT_FAILURE = 0x1,
|
|
|
|
|
|
|
|
// For classes that could realloc a buffer in order to grow or
|
|
|
|
// shrink the size of the fuzzed result, this results in having
|
|
|
|
// two different buffers that need to be freed. To make the calling
|
|
|
|
// code work correctly, we can use the flag below to transfer the
|
|
|
|
// allocation ownership such that the calling code frees the correct
|
|
|
|
// buffer and our fuzz classes frees the other buffer.
|
|
|
|
// Example:
|
|
|
|
// DWORD cbSize = 0;
|
2019-06-11 22:27:09 +02:00
|
|
|
// __untrusted_array_size(BYTE, DWORD) cbSizeUntrusted =
|
2019-05-03 00:29:04 +02:00
|
|
|
// __untrusted_array_size_init(BYTE, DWORD)(cbSize);
|
2019-06-11 22:27:09 +02:00
|
|
|
// __untrusted_array(BYTE, DWORD) arr =
|
2019-05-03 00:29:04 +02:00
|
|
|
// __untrusted_array_init<BYTE, DWORD>(FUZZ_MAP(...), nullptr, cbSizeUntrusted);
|
|
|
|
// AllocateArray(&arr, &cbSizeUntrusted); // arr overloads & operator to
|
|
|
|
// // allow allocation and then wraps
|
|
|
|
// // this allocation with CFuzzArray
|
|
|
|
// ...use arr, potentially resulting in a reallocated fuzzed buffer...
|
|
|
|
// CoTaskMemFree(arr); // If reallocation occurs, the other buffer
|
|
|
|
// // will be freed when arr goes out of scope.
|
|
|
|
TRAIT_TRANSFER_ALLOCATION = 0x2,
|
|
|
|
|
|
|
|
// Given the design of the CFuzzArray class, it could be unclear
|
|
|
|
// if the corresponding size of the array is the number of elements
|
|
|
|
// or the overall byte count. The class defaults to assuming
|
2019-06-11 22:27:09 +02:00
|
|
|
// the number of elements, but the trait below can be used to
|
2019-05-03 00:29:04 +02:00
|
|
|
// inform the class that the size is actually the number of total
|
|
|
|
// bytes. Note that when using byte arrays, there is no difference
|
|
|
|
// in behavior.
|
|
|
|
TRAIT_SIZE_IS_BCOUNT = 0x4
|
|
|
|
};
|
|
|
|
typedef UINT FuzzTraits;
|
|
|
|
|
|
|
|
// Percentages used for fuzzing are converted into a range of acceptable
|
|
|
|
// values between 0 and 100. This allows a random value to be generated
|
|
|
|
// between 0 and 100, if it falls within the range then the fuzzing
|
|
|
|
// manipulation will be applied accordingly.
|
|
|
|
// For example: Generate a random value between 0-100 (inclusive)
|
|
|
|
// _Range_ | _Manipulation_
|
|
|
|
// 91-100 | Fuzz permutation A
|
|
|
|
// 86-90 | Fuzz permutation B
|
|
|
|
// 80-85 | Fuzz permutation C
|
|
|
|
// 0-79 | Default value
|
|
|
|
struct _range
|
|
|
|
{
|
|
|
|
int iHigh;
|
|
|
|
int iLow;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Fuzz type entries provide a fuzzing function, specified as pfnFuzz,
|
2019-06-11 22:27:09 +02:00
|
|
|
// together with a percentage that this fuzzing function should be
|
2019-05-03 00:29:04 +02:00
|
|
|
// invoked. The percentage, uiPercentage, should be between 1-100.
|
2019-06-11 22:27:09 +02:00
|
|
|
// There are some fuzzing classes (i.e. CFuzzString) that allow
|
|
|
|
// for fuzzed values to be reallocated, in these cases a function
|
|
|
|
// must be specified via pfnDealloc that can free the resulting
|
|
|
|
// memory appropriately. If no memory is being reallocated, pfnDealloc
|
2019-05-03 00:29:04 +02:00
|
|
|
// can be nullptr.
|
|
|
|
//
|
2019-06-11 22:27:09 +02:00
|
|
|
// An array of fuzz type entries (or fuzz array entries) is referred
|
2019-05-03 00:29:04 +02:00
|
|
|
// to as a fuzz map in subsequent documentation.
|
|
|
|
//
|
|
|
|
// The design of pfnFuzz is to allow for mutational based fuzzing
|
|
|
|
// scenarios, where "template" data is passed to the fuzzing routine
|
|
|
|
// via the function parameter. This data will be whatever the
|
|
|
|
// fuzzing class' value is, either from initialization of the class
|
|
|
|
// or by setting the value directly.
|
2019-06-11 22:27:09 +02:00
|
|
|
// For example:
|
|
|
|
// __untrusted_lpwstr pwsz =
|
2019-05-03 00:29:04 +02:00
|
|
|
// __untrusted_lpwstr_init(FUZZ_MAP(...), L"foo");
|
|
|
|
// LPWSTR pwszFuzzed = pwsz; // Asking for the LPWSTR member will
|
2019-06-11 22:27:09 +02:00
|
|
|
// // cause the fuzzing map to be
|
2019-05-03 00:29:04 +02:00
|
|
|
// // evaluated, if a fuzz type entry is
|
|
|
|
// // selected, L"foo" will be passed
|
|
|
|
// // as the parameter to pfnFuzz
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type, typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
struct _fuzz_type_entry
|
|
|
|
{
|
|
|
|
unsigned int uiPercentage;
|
|
|
|
std::function<_Type(_Type, _Args...)> pfnFuzz;
|
|
|
|
std::function<void(_Type)> pfnDealloc;
|
|
|
|
};
|
|
|
|
|
|
|
|
// The range structure is an internal structure that maps the percentage
|
|
|
|
// specified within the fuzz type entry struct into its associated
|
|
|
|
// probability range. It is not expected that users of this codebase
|
|
|
|
// will need to use this struct type directly.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type, typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
struct _range_fuzz_type_entry
|
|
|
|
{
|
|
|
|
_fuzz_type_entry<_Type, _Args...> fte;
|
|
|
|
_range range;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Similar to fuzz type entries, there are different challenges when
|
|
|
|
// fuzzing an array, since the size of the array needs to be known
|
|
|
|
// and if a reallocation occurs, the size needs to be updated to stay
|
|
|
|
// in sync. To support this, fuzz array entries have two template
|
|
|
|
// parameters, the first one is the type of objects in the array,
|
|
|
|
// and the second parameter is the size, either in bytes or in element
|
2019-06-11 22:27:09 +02:00
|
|
|
// count. When designing a fuzz map for an array, you will need to
|
2019-05-03 00:29:04 +02:00
|
|
|
// determine whether _Type2 is the byte count or the element count.
|
|
|
|
//
|
2019-06-11 22:27:09 +02:00
|
|
|
// With respect to pfnFuzz, once again this follows a mutational
|
2019-05-03 00:29:04 +02:00
|
|
|
// based approach, where the parameters will be whatever CFuzzArray
|
2019-06-11 22:27:09 +02:00
|
|
|
// is initialized to. Notice that the second parameter is an
|
2019-05-03 00:29:04 +02:00
|
|
|
// automatic reference to the size, which allows this value to be
|
|
|
|
// updated in the event that a new fuzzed buffer is allocation and
|
|
|
|
// returned from pfnFuzz. If reallocation occurs, pfnDealloc must
|
|
|
|
// be provided as a means of appropriately freeing the memory.
|
|
|
|
// For example:
|
|
|
|
// DWORD cbSize = 0;
|
|
|
|
// __untrusted_array_size(BYTE, DWORD) cbSizeUntrusted =
|
|
|
|
// __untrusted_array_size_init<BYTE, DWORD>(cbSize);
|
2019-06-11 22:27:09 +02:00
|
|
|
// __untrusted_array(BYTE, DWORD) arr =
|
2019-05-03 00:29:04 +02:00
|
|
|
// __untrusted_array_init<BYTE, DWORD>(FUZZ_MAP(...), nullptr, cbSizeUntrusted);
|
2019-06-11 22:27:09 +02:00
|
|
|
// AllocateArray(&arr, &cbSizeUntrusted); // Operator overloading on & will
|
2019-05-03 00:29:04 +02:00
|
|
|
// // allow the array to be allocated
|
|
|
|
// // and then wrapped by CFuzzArray
|
|
|
|
// BYTE *rgFuzzed = arr; // Asking for the BYTE* value will cause
|
|
|
|
// // the fuzz map to be evaluated. If the
|
|
|
|
// // buffer is reallocated, pfnFuzz will
|
|
|
|
// // have a reference to cbSize which can be
|
|
|
|
// // updated appropriately.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type1, typename _Type2, typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
struct _fuzz_array_entry
|
|
|
|
{
|
|
|
|
unsigned int uiPercentage;
|
2019-06-11 22:27:09 +02:00
|
|
|
std::function<_Type1*(_Type1*, _Type2&, _Args...)> pfnFuzz;
|
2019-05-03 00:29:04 +02:00
|
|
|
std::function<void(_Type1*)> pfnDealloc;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Internal struct for mapping percentages to value ranges. Not
|
|
|
|
// expected to be used by users of this codebase but for internal
|
|
|
|
// use instead.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type1, typename _Type2, typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
struct _range_fuzz_array_entry
|
|
|
|
{
|
|
|
|
_fuzz_array_entry<_Type1, _Type2, _Args...> fae;
|
|
|
|
_range range;
|
|
|
|
};
|
|
|
|
|
|
|
|
// During initialization of the fuzz classes, if the fuzz map
|
2019-06-11 22:27:09 +02:00
|
|
|
// percentages add up to more than 100% and the fuzz trait
|
2019-05-03 00:29:04 +02:00
|
|
|
// TRAIT_THROW_ON_INIT_FAILURE is applied, the CFuzzRangeException
|
|
|
|
// will be thrown. Since constructors cannot return errors, this allows
|
|
|
|
// for verifying that numeric errors have not been made when designing
|
|
|
|
// the fuzz map that would cause fuzzing manipulations to not ever
|
|
|
|
// be applied. Not that this exception cannot ever be thrown from
|
|
|
|
// CFuzzFlags, as the fuzz map is evaluated slightly differently when
|
|
|
|
// fuzzing bit-wise flags.
|
|
|
|
class CFuzzRangeException
|
|
|
|
{
|
|
|
|
public:
|
2019-06-11 22:27:09 +02:00
|
|
|
CFuzzRangeException(){};
|
|
|
|
virtual ~CFuzzRangeException(){};
|
2019-05-03 00:29:04 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// In an effort to avoid fuzzing code from scattering rand() throughout
|
|
|
|
// the codebase, the CFuzzChance class is designed as the go to place
|
|
|
|
// for generating random values (or random selection of values). This
|
2019-06-11 22:27:09 +02:00
|
|
|
// class is also used by the various fuzz classes internally for
|
2019-05-03 00:29:04 +02:00
|
|
|
// determining which fuzzing routine should be applied from the fuzz map.
|
|
|
|
class CFuzzChance
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// Will collide with min() and max() macros, so we need to jump through hoops
|
|
|
|
// to correctly use std::numeric_limits<_Type>::min() and std::numeric_limits<_Type>::max()
|
|
|
|
#ifdef min
|
|
|
|
#define __min_collision__
|
|
|
|
#undef min
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef max
|
|
|
|
#define __max_collision__
|
|
|
|
#undef max
|
|
|
|
#endif
|
|
|
|
template<class _Type>
|
2019-06-11 22:27:09 +02:00
|
|
|
static _Type GetRandom() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return GetRandom<_Type>(std::numeric_limits<_Type>::min(), std::numeric_limits<_Type>::max());
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class _Type>
|
|
|
|
static _Type GetRandom(__in _Type tCap) throw()
|
|
|
|
{
|
|
|
|
return GetRandom<_Type>(std::numeric_limits<_Type>::min(), --tCap);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class _Type>
|
|
|
|
static _Type GetRandom(__in _Type tMin, __in _Type tMax)
|
|
|
|
{
|
|
|
|
std::mt19937 engine(m_rd()); // Mersenne twister MT19937
|
|
|
|
std::uniform_int_distribution<_Type> distribution(tMin, tMax);
|
|
|
|
auto generator = std::bind(distribution, engine);
|
|
|
|
return generator();
|
|
|
|
}
|
|
|
|
|
|
|
|
// uniform_int_distribution only works with _Is_IntType types, which do not
|
|
|
|
// currently include char or unsigned char, so here is a specialization
|
|
|
|
// specifically for BYTE (unsigned char).
|
|
|
|
template<>
|
|
|
|
static BYTE GetRandom(__in BYTE tMin, __in BYTE tMax)
|
|
|
|
{
|
|
|
|
std::mt19937 engine(m_rd()); // Mersenne twister MT19937
|
2020-02-10 21:40:01 +01:00
|
|
|
// BYTE is unsigned, so we want to also use an unsigned type to avoid sign
|
2019-05-03 00:29:04 +02:00
|
|
|
// extension of tMin and tMax.
|
|
|
|
std::uniform_int_distribution<unsigned short> distribution(tMin, tMax);
|
|
|
|
auto generator = std::bind(distribution, engine);
|
|
|
|
return static_cast<BYTE>(generator());
|
|
|
|
}
|
|
|
|
#ifdef __min_collision__
|
|
|
|
#undef __min_collision__
|
2019-06-11 22:27:09 +02:00
|
|
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
2019-05-03 00:29:04 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __max_collision__
|
|
|
|
#undef __max_collision__
|
2019-06-11 22:27:09 +02:00
|
|
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
2019-05-03 00:29:04 +02:00
|
|
|
#endif
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// Given an array of elements, select a random element from the
|
2019-05-03 00:29:04 +02:00
|
|
|
// collection. Note that cElems is the number of items in the array.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type>
|
|
|
|
static _Type SelectOne(__in_ecount(cElems) const _Type* rg, __in size_t cElems) throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return rg[GetRandom<size_t>(cElems)];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given an array of elements, select a random element from the
|
|
|
|
// collection. Note that _cElems is the number of items in the array.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type, size_t _cElems>
|
2019-05-03 00:29:04 +02:00
|
|
|
static _Type SelectOne(const _Type (&rg)[_cElems]) throw()
|
|
|
|
{
|
|
|
|
return rg[GetRandom<size_t>(_cElems)];
|
|
|
|
}
|
2019-06-11 22:27:09 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
private:
|
2019-06-11 22:27:09 +02:00
|
|
|
CFuzzChance() {}
|
|
|
|
virtual ~CFuzzChance() {}
|
2019-05-03 00:29:04 +02:00
|
|
|
static std::random_device m_rd;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::random_device CFuzzChance::m_rd;
|
|
|
|
|
|
|
|
// Provides a common base class between CFuzzArray and CFuzzType,
|
|
|
|
// collecting the set of members that are used by both classes. This
|
|
|
|
// class cannot be instantiated directly and must be inherited from.
|
|
|
|
class CFuzzBase
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
CFuzzBase() :
|
|
|
|
m_fFuzzed(FALSE),
|
2019-06-11 22:27:09 +02:00
|
|
|
m_iPercentageTotal(100){};
|
|
|
|
virtual ~CFuzzBase(){};
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
// Converts a percentage into a valid range. Note that riTotal
|
|
|
|
// is a reference value, which allows for a running total to be
|
|
|
|
// decremented as fuzz map percentages are mapped to valid ranges.
|
|
|
|
void ConvertPercentageToRange(__in unsigned int iPercentage,
|
2019-06-11 22:27:09 +02:00
|
|
|
__inout int& riTotal,
|
|
|
|
__deref_out _range* pr) const
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
pr->iHigh = riTotal;
|
|
|
|
pr->iLow = riTotal - iPercentage;
|
|
|
|
riTotal -= iPercentage;
|
|
|
|
}
|
2019-06-11 22:27:09 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
protected:
|
|
|
|
BOOL m_fFuzzed;
|
|
|
|
int m_iPercentageTotal;
|
|
|
|
FuzzTraits m_traits{ TRAIT_DEFAULT };
|
|
|
|
};
|
|
|
|
|
|
|
|
// The CFuzzArray class is designed to allow fuzzing of element
|
|
|
|
// arrays, potentially reallocating a fuzzed version of the array
|
|
|
|
// that is either larger or smaller than the template buffer. Whether
|
|
|
|
// reallocation is possible (or an appropriate fuzzing strategy) is
|
|
|
|
// dependent on the scenario and must be determined by the person
|
|
|
|
// designing the fuzz map. If reallocation is going to be used, the
|
|
|
|
// _Alloc class must specify the appropriate allocator that corresponds
|
|
|
|
// to the code that is being fuzzed. For example, if all allocations
|
|
|
|
// are made using new/delete, the default CComAllocator is not
|
|
|
|
// appropriate and should be changed to CCRTAllocator. Adding new
|
|
|
|
// allocator classes is as easy as writing a new class that supports
|
|
|
|
// Allocate/Free/Reallocate, see documentation for CComAllocator.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<class _Alloc, typename _Type1, typename _Type2, typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
class CFuzzArray : public CFuzzBase
|
|
|
|
{
|
|
|
|
public:
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type1, typename _Type2, typename... _Args>
|
|
|
|
friend class CFuzzArraySize;
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2020-02-10 21:40:01 +01:00
|
|
|
// Creates a CFuzzArray instance that wraps a buffer specified by
|
2019-05-03 00:29:04 +02:00
|
|
|
// rg, together with its size (note that this is the number of elements
|
|
|
|
// not necessarily the byte count). cElems is a reference so it must
|
|
|
|
// point to a valid variable. In this constructor, it is valid for
|
|
|
|
// the fuzz map to be a null pointer, but it is expected that a fuzz
|
2019-06-11 22:27:09 +02:00
|
|
|
// map will be provided at a later time via SetFuzzArrayMap or
|
2019-05-03 00:29:04 +02:00
|
|
|
// AddFuzzArrayEntry.
|
|
|
|
//
|
|
|
|
// If CFuzzArray is initialized with rg == nullptr, this usage case
|
|
|
|
// is designed to leverage the & operator overload to have CFuzzArray
|
|
|
|
// initialized to a valid buffer. In this scenario, if reallocation
|
|
|
|
// is being used by the fuzz map and reallocation occurs, this class
|
|
|
|
// implements logic to transfer the fuzzed allocation to the calling code
|
|
|
|
// and then free the array that was set via the & operator. If this is
|
|
|
|
// not desirable, the situation is avoided by either not reallocating
|
|
|
|
// or by not initializing via &.
|
|
|
|
CFuzzArray(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfae) const _fuzz_array_entry<_Type1, _Type2, _Args...>* rgfae,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfae,
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount_opt(cElems) _Type1* rg,
|
2019-05-03 00:29:04 +02:00
|
|
|
__inout _Type2& cElems,
|
|
|
|
__in _Args&&... args) :
|
2019-06-11 22:27:09 +02:00
|
|
|
m_rgCaller(rg),
|
|
|
|
m_pcElems(&cElems),
|
|
|
|
m_pfas(nullptr),
|
|
|
|
m_tArgs(std::forward<_Args>(args)...)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
Init(rgfae, cfae);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constructor that allows association with a companion CFuzzArraySize object.
|
|
|
|
// See CFuzzArraySize comments for more details.
|
|
|
|
CFuzzArray(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfae) const _fuzz_array_entry<_Type1, _Type2, _Args...>* rgfae,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfae,
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_opt _Type1* rg,
|
|
|
|
__in CFuzzArraySize<_Type1, _Type2, _Args...>& size,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in _Args&&... args) :
|
2019-06-11 22:27:09 +02:00
|
|
|
m_rgCaller(rg),
|
|
|
|
m_pcElems(size.m_pcElems),
|
|
|
|
m_pfas(nullptr),
|
|
|
|
m_tArgs(std::forward<_Args>(args)...)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
if (SUCCEEDED(Init(rgfae, cfae)))
|
|
|
|
{
|
|
|
|
size.Pair(*this);
|
|
|
|
m_pfas = size.Reference();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~CFuzzArray()
|
|
|
|
{
|
|
|
|
FreeRealloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Requesting the array pointer will result in the fuzz map being
|
|
|
|
// evaluated, potentially returning a fuzzed value. Note that fuzzing
|
|
|
|
// is only evaluated once, so repeated access will return the same
|
|
|
|
// fuzzed choice.
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline operator _Type1*() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return GetValueFromMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow calls to get the size of the fuzzed array ensuring evaluation
|
|
|
|
// of the fuzzmap. Designed primarily to be called from the CFuzzArraySize
|
|
|
|
// friend class.
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline operator _Type2() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
GetValueFromMap();
|
|
|
|
return *m_pcElems;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The overloaded & operator allows this class to replace array pointers
|
|
|
|
// within the calling code, but the associated size need to be initialized
|
|
|
|
// via the constructor. If this operator is used and the fuzzing map
|
|
|
|
// applies reallocation, ownership of the respective buffers is transferred
|
|
|
|
// such that the fuzzed buffer becomes the caller's responsibility and the
|
2019-06-11 22:27:09 +02:00
|
|
|
// initial buffer is freed when this class is destroyed. Users of this
|
2019-05-03 00:29:04 +02:00
|
|
|
// codebase are responsible for ensuring the correct allocator is specified
|
|
|
|
// for _Alloc and that the calling code is still functionally correct.
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline _Type1** operator&() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
assert(m_rgCaller == nullptr);
|
|
|
|
m_ftEffectiveTraits |= TRAIT_TRANSFER_ALLOCATION;
|
|
|
|
return (m_rgRealloc) ? &m_rgRealloc : &m_rgCaller;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Const version of this operator overload does not assume ownership transfer
|
2019-06-11 22:27:09 +02:00
|
|
|
// like the above case.
|
|
|
|
__inline const _Type1** operator&() const throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
assert(m_rgCaller == nullptr);
|
|
|
|
return (m_rgRealloc) ? &m_rgRealloc : &m_rgCaller;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// Setting the fuzz map will clear any previous applied fuzz map. The
|
|
|
|
// AddFuzzArrayEntry function can be used to add additional fuzz map
|
|
|
|
// entries without removing the existing map. Returns E_INVALIDARG in the
|
2019-05-03 00:29:04 +02:00
|
|
|
// event that the total percentages add up to more than 100%.
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] __inline HRESULT SetFuzzArrayMap(
|
|
|
|
__in_ecount(cfae) const _fuzz_array_entry<_Type1, _Type2, _Args...>* rgfae,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfae) throw()
|
|
|
|
{
|
|
|
|
ClearFuzzArrayEntries();
|
|
|
|
for (ULONG i = 0; i < cfae; i++)
|
|
|
|
{
|
|
|
|
AddFuzzArrayEntry(rgfae[i].uiPercentage, rgfae[i].pfnFuzz, rgfae[i].pfnDealloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (m_iPercentageTotal >= 0) ? S_OK : E_INVALIDARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adds an additional fuzz map entry, without clearing the existing
|
|
|
|
// fuzz map. Returns E_INVALIDARG in the event that the total percentages
|
|
|
|
// add up to more than 100%.
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT AddFuzzArrayEntry(
|
2019-05-03 00:29:04 +02:00
|
|
|
__in unsigned int uiPercentage,
|
2019-06-11 22:27:09 +02:00
|
|
|
__in std::function<_Type1*(_Type1*, _Type2&, _Args...)> pfnFuzz,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in std::function<void(_Type1*)> pfnDealloc = nullptr) throw()
|
|
|
|
{
|
|
|
|
_range_fuzz_array_entry<_Type1, _Type2, _Args...> r = { 0 };
|
|
|
|
r.fae.uiPercentage = uiPercentage;
|
|
|
|
r.fae.pfnFuzz = pfnFuzz;
|
|
|
|
r.fae.pfnDealloc = pfnDealloc;
|
|
|
|
ConvertPercentageToRange(uiPercentage, m_iPercentageTotal, &r.range);
|
|
|
|
m_map.push_back(r);
|
|
|
|
return (m_iPercentageTotal >= 0) ? S_OK : E_INVALIDARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClearFuzzArrayEntries() throw()
|
|
|
|
{
|
|
|
|
m_map.clear();
|
|
|
|
m_iPercentageTotal = 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invokes the fuzz map in the event that fuzzing as not been applied.
|
|
|
|
// Since the fuzz map entries have their own potential allocation and
|
2019-06-11 22:27:09 +02:00
|
|
|
// deallocation routines, we actually make another copy of the fuzzed
|
2019-05-03 00:29:04 +02:00
|
|
|
// buffer in the event that reallocation has occurred (determined by
|
2019-06-11 22:27:09 +02:00
|
|
|
// comparing against the original initialized pointer value). This
|
2019-05-03 00:29:04 +02:00
|
|
|
// is important because we use the _Alloc value to ensure the correct
|
|
|
|
// memory allocator is used that is appropriate for the calling code.
|
|
|
|
__inline _Type1* GetValueFromMap()
|
|
|
|
{
|
|
|
|
if (!m_fFuzzed)
|
|
|
|
{
|
|
|
|
m_fFuzzed = TRUE;
|
|
|
|
WORD wRandom = CFuzzChance::GetRandom<WORD>(100);
|
2019-06-11 22:27:09 +02:00
|
|
|
for (auto& r : m_map)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
if (r.range.iLow <= wRandom && wRandom < r.range.iHigh)
|
|
|
|
{
|
2019-06-11 22:27:09 +02:00
|
|
|
_Type1* rgTemp = CallFuzzMapFunction(r.fae.pfnFuzz, m_rgCaller, *m_pcElems, m_tArgs);
|
2019-05-03 00:29:04 +02:00
|
|
|
if (rgTemp && rgTemp != m_rgCaller)
|
|
|
|
{
|
|
|
|
size_t cbRealloc = (m_ftEffectiveTraits & TRAIT_SIZE_IS_BCOUNT) ?
|
2019-06-11 22:27:09 +02:00
|
|
|
*m_pcElems :
|
|
|
|
*m_pcElems * sizeof(_Type1);
|
2019-05-03 00:29:04 +02:00
|
|
|
m_rgRealloc = reinterpret_cast<_Type1*>(_Alloc::Allocate(cbRealloc));
|
|
|
|
if (m_rgRealloc)
|
|
|
|
{
|
|
|
|
memcpy_s(m_rgRealloc, cbRealloc, rgTemp, cbRealloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r.fae.pfnDealloc)
|
|
|
|
{
|
|
|
|
r.fae.pfnDealloc(rgTemp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (m_rgRealloc) ? m_rgRealloc : m_rgCaller;
|
|
|
|
}
|
2019-06-11 22:27:09 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
private:
|
|
|
|
_Type1* m_rgCaller;
|
|
|
|
_Type1* m_rgRealloc;
|
2019-06-11 22:27:09 +02:00
|
|
|
_Type2* m_pcElems;
|
2019-05-03 00:29:04 +02:00
|
|
|
FuzzTraits m_ftEffectiveTraits;
|
|
|
|
CFuzzArraySize<_Type1, _Type2, _Args...>* m_pfas;
|
2019-06-11 22:27:09 +02:00
|
|
|
std::vector<_range_fuzz_array_entry<_Type1, _Type2, _Args...>> m_map;
|
2019-05-03 00:29:04 +02:00
|
|
|
std::tuple<_Args...> m_tArgs;
|
|
|
|
|
|
|
|
CFuzzArray<__FUZZING_ALLOCATOR, _Type1, _Type2, _Args...>* Reference()
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
template<int... Is>
|
2019-05-03 00:29:04 +02:00
|
|
|
_Type1* CallFuzzMapFunction(
|
2019-06-11 22:27:09 +02:00
|
|
|
std::function<_Type1*(_Type1*, _Type2&, _Args...)> pfnFuzz,
|
|
|
|
_Type1* t1,
|
|
|
|
_Type2& t2,
|
2019-05-03 00:29:04 +02:00
|
|
|
std::tuple<_Args...>& tup,
|
|
|
|
variadic::index<Is...>)
|
|
|
|
{
|
|
|
|
return pfnFuzz(t1, t2, std::get<Is>(tup)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
_Type1* CallFuzzMapFunction(
|
2019-06-11 22:27:09 +02:00
|
|
|
std::function<_Type1*(_Type1*, _Type2&, _Args...)> pfnFuzz,
|
|
|
|
_Type1* t1,
|
|
|
|
_Type2& t2,
|
2019-05-03 00:29:04 +02:00
|
|
|
std::tuple<_Args...>& tup)
|
|
|
|
{
|
2019-06-11 22:27:09 +02:00
|
|
|
return CallFuzzMapFunction(pfnFuzz, t1, t2, tup, variadic::gen_seq<sizeof...(_Args)>{});
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT Init(
|
|
|
|
__in_ecount(cfae) const _fuzz_array_entry<_Type1, _Type2, _Args...>* rgfae,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfae)
|
|
|
|
{
|
|
|
|
m_rgRealloc = nullptr;
|
|
|
|
m_ftEffectiveTraits = m_traits;
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// Since constructors cannot return error values, the
|
2019-05-03 00:29:04 +02:00
|
|
|
// TRAIT_THROW_ON_INIT_FAILURE trait allows for an exception
|
|
|
|
// to be thrown in the event that this class was not initialized
|
|
|
|
// correctly. The intended purpose is to catch users of this
|
|
|
|
// codebase who have incorrectly specified fuzz maps that add up
|
|
|
|
// to more than 100%.
|
2019-05-30 18:20:42 +02:00
|
|
|
HRESULT hr = SetFuzzArrayMap(rgfae, cfae);
|
2019-05-03 00:29:04 +02:00
|
|
|
if (FAILED(hr) && (m_traits & TRAIT_THROW_ON_INIT_FAILURE))
|
|
|
|
{
|
|
|
|
throw CFuzzRangeException();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_rgCaller == nullptr)
|
|
|
|
{
|
|
|
|
m_ftEffectiveTraits |= TRAIT_TRANSFER_ALLOCATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeRealloc()
|
|
|
|
{
|
|
|
|
if (m_rgRealloc)
|
|
|
|
{
|
|
|
|
// See comments about explaining when we transfer
|
|
|
|
// allocation and deallocation responsibilities.
|
|
|
|
if (m_ftEffectiveTraits & TRAIT_TRANSFER_ALLOCATION)
|
|
|
|
{
|
|
|
|
_Alloc::Free(m_rgCaller);
|
|
|
|
m_rgCaller = nullptr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_Alloc::Free(m_rgRealloc);
|
|
|
|
m_rgRealloc = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// When working with arrays, care must be taken when passing a pointer to a
|
2019-05-03 00:29:04 +02:00
|
|
|
// fuzzed array together with the size to ensure the size lines up with the
|
|
|
|
// the evaluated fuzz map. Consider the following:
|
|
|
|
//
|
|
|
|
// BYTE rg[10] = {0};
|
|
|
|
// size_t cb = ARRAYSIZE(rg);
|
|
|
|
// CFuzzArray<BYTE, size_t> rgUntrusted(FUZZ_MAP(...), rg, cb);
|
|
|
|
// hr = foo(rgUntrusted, cb);
|
|
|
|
//
|
|
|
|
// When evaluating the arguments for the function foo, the value of cb
|
|
|
|
// will be pushed as an argument before fa has a chance to evaluate the fuzzing map.
|
|
|
|
// This results in the cb parameter to foo being the original value, even if the
|
|
|
|
// fuzzing map alters cb.
|
|
|
|
//
|
|
|
|
// To account for this CFuzzArraySize pairs together with a CFuzzArray instance to ensure
|
|
|
|
// the fuzz map is evaluated prior to either the array pointer or the size being used.
|
|
|
|
// For example:
|
|
|
|
//
|
|
|
|
// BYTE rg[10] = {0};
|
|
|
|
// size_t cb = ARRAYSIZE(rg);
|
|
|
|
// __untrusted_array_size(BYTE, size_t) cbUntrusted = __untrusted_array_size_init<BYTE, size_t>(cb);
|
|
|
|
// __untrusted_array(BYTE, size_t) rgUntrusted = __untrusted_array_init<BYTE, size_t>(FUZZ_MAP(...), rg, cbUntrusted);
|
|
|
|
// hr = foo(rgUntrusted, cbUntrusted);
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type1, typename _Type2, typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
class CFuzzArraySize
|
|
|
|
{
|
|
|
|
public:
|
2019-06-11 22:27:09 +02:00
|
|
|
template<class _Alloc, typename _Type1, typename _Type2, typename... _Args>
|
|
|
|
friend class CFuzzArray;
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
CFuzzArraySize(__inout _Type2& cElems) :
|
|
|
|
m_pcElems(&cElems),
|
|
|
|
m_pfa(nullptr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
virtual ~CFuzzArraySize() {}
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline operator _Type2() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
if (m_pfa)
|
|
|
|
{
|
|
|
|
m_pfa->GetValueFromMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
return *m_pcElems;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline _Type2* operator&() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return m_pcElems;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline const _Type2* operator&() const throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return m_pcElems;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline void Pair(__in CFuzzArray<__FUZZING_ALLOCATOR, _Type1, _Type2, _Args...>& rfa)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
m_pfa = rfa.Reference();
|
|
|
|
}
|
2019-06-11 22:27:09 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
private:
|
2019-06-11 22:27:09 +02:00
|
|
|
CFuzzArray<__FUZZING_ALLOCATOR, _Type1, _Type2, _Args...>* m_pfa;
|
|
|
|
_Type2* m_pcElems;
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
CFuzzArraySize<_Type1, _Type2, _Args...>* Reference()
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// The CFuzzType class is primarily designed for primitive types but
|
|
|
|
// is also used as the base class for CFuzzTypePtr and CFuzzLpwstr.
|
|
|
|
// The various operator overloads allow this class to wrap a type and
|
2019-06-11 22:27:09 +02:00
|
|
|
// usage of that type works transparently. Asking for the value
|
2019-05-03 00:29:04 +02:00
|
|
|
// of the type wrapped by this class will invoke the fuzzing map.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type, typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
class CFuzzType : public CFuzzBase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// Creates an instance of CFuzzType, initializing the value to
|
|
|
|
// the value specified in t. Note that providing a fuzz map
|
|
|
|
// is optional, but then expected to be provided via SetFuzzTypeMap
|
|
|
|
// or AddFuzzTypeEntry if fuzzing is to be applied.
|
|
|
|
CFuzzType(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfte) const _fuzz_type_entry<_Type, _Args...>* rgfte,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfte,
|
|
|
|
__in _Type t,
|
|
|
|
__in _Args&&... args) :
|
2019-06-11 22:27:09 +02:00
|
|
|
m_t(t),
|
|
|
|
m_tInit(t),
|
|
|
|
m_tArgs(std::forward<_Args>(args)...)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
m_pfnOnFuzzedValueFromMap = [](_Type t, std::function<void(_Type)>) { return t; };
|
|
|
|
HRESULT hr = SetFuzzTypeMap(rgfte, cfte);
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// Since constructors cannot return error values, the
|
2019-05-03 00:29:04 +02:00
|
|
|
// TRAIT_THROW_ON_INIT_FAILURE trait allows for an exception
|
|
|
|
// to be thrown in the event that this class was not initialized
|
|
|
|
// correctly. The intended purpose is to catch users of this
|
|
|
|
// codebase who have incorrectly specified fuzz maps that add up
|
|
|
|
// to more than 100%.
|
|
|
|
if (FAILED(hr) && (m_traits & TRAIT_THROW_ON_INIT_FAILURE))
|
|
|
|
{
|
|
|
|
throw CFuzzRangeException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~CFuzzType()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// Initializes with the value specified by t and then applies
|
2019-05-03 00:29:04 +02:00
|
|
|
// the fuzz map to produce a fuzzed return value. Usage of this
|
|
|
|
// operator will make the CFuzzType instance look like a function
|
|
|
|
// call, which might be desirable in some instances.
|
|
|
|
// For example:
|
|
|
|
// __untrusted_t(int) iVal = __untrusted_init<int>(FUZZ_MAP(...), 10);
|
|
|
|
// int iFuzzedVal = iVal(15); // re-initializes the default value to 15,
|
|
|
|
// // then applies the fuzz map to return
|
|
|
|
// // a potentially fuzzed value
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline _Type operator()(__in _Type t) throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
m_t = m_tInit = t;
|
|
|
|
return GetValueFromMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Will reinitialize the value for the internally wrapped type.
|
|
|
|
// If the fuzzing map has already been evaluated, initializing
|
|
|
|
// via the = operator will not cause the fuzzing map to be
|
|
|
|
// evaluated when the value is subsequently retrieved.
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline void operator=(__in _Type t) throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
m_t = m_tInit = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Getting the value of this instance will cause the fuzz map
|
|
|
|
// to be evaluated. The fuzz map will only be evaluated once,
|
|
|
|
// subsequent access will always return the selected value.
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline operator _Type() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return GetValueFromMap();
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// Allows initialization of the internal type by providing a
|
2019-05-03 00:29:04 +02:00
|
|
|
// reference. If the fuzz map has been evaluated, the reference
|
|
|
|
// is provided to the fuzzed value.
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline virtual _Type* operator&() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return (m_fFuzzed) ? &m_t : &m_tInit;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Similar to above, if the fuzz map has been evaluated, the
|
|
|
|
// reference is provided to the fuzzed value.
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline const _Type* operator&() const throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return (m_fFuzzed) ? &m_t : &m_tInit;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// Setting the fuzz map will clear any previous applied fuzz map. The
|
|
|
|
// AddFuzzArrayEntry function can be used to add additional fuzz map
|
|
|
|
// entries without removing the existing map. Returns E_INVALIDARG in the
|
2019-05-03 00:29:04 +02:00
|
|
|
// event that the total percentages add up to more than 100%.
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] __inline HRESULT SetFuzzTypeMap(
|
|
|
|
__in_ecount(cfte) const _fuzz_type_entry<_Type, _Args...>* rgfte,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfte) throw()
|
|
|
|
{
|
|
|
|
ClearFuzzTypeEntries();
|
2019-05-30 18:20:42 +02:00
|
|
|
|
|
|
|
bool fInvalidEntry{};
|
|
|
|
for (ULONG i{}; i < cfte; ++i)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2019-05-30 18:20:42 +02:00
|
|
|
// Process all entries; failure will be returned at the end.
|
|
|
|
fInvalidEntry |= FAILED(AddFuzzTypeEntry(rgfte[i].uiPercentage, rgfte[i].pfnFuzz, rgfte[i].pfnDealloc));
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2019-05-30 18:20:42 +02:00
|
|
|
return (fInvalidEntry || (m_iPercentageTotal >= 0)) ? S_OK : E_INVALIDARG;
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Adds an additional fuzz map entry, without clearing the existing
|
|
|
|
// fuzz map. Returns E_INVALIDARG in the event that the total percentages
|
|
|
|
// add up to more than 100%.
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT AddFuzzTypeEntry(
|
2019-05-03 00:29:04 +02:00
|
|
|
__in unsigned int uiPercentage,
|
|
|
|
__in std::function<_Type(_Type, _Args...)> pfnFuzz,
|
|
|
|
__in std::function<void(_Type)> pfnDealloc = nullptr) throw()
|
|
|
|
{
|
|
|
|
_range_fuzz_type_entry<_Type, _Args...> r = { 0 };
|
|
|
|
r.fte.uiPercentage = uiPercentage;
|
|
|
|
r.fte.pfnFuzz = pfnFuzz;
|
|
|
|
r.fte.pfnDealloc = pfnDealloc;
|
|
|
|
ConvertPercentageToRange(uiPercentage, m_iPercentageTotal, &r.range);
|
|
|
|
m_map.push_back(r);
|
|
|
|
return (m_iPercentageTotal >= 0) ? S_OK : E_INVALIDARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClearFuzzTypeEntries() throw()
|
|
|
|
{
|
|
|
|
m_map.clear();
|
|
|
|
m_iPercentageTotal = 100;
|
|
|
|
}
|
2019-06-11 22:27:09 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
protected:
|
|
|
|
_Type m_t;
|
|
|
|
_Type m_tInit;
|
2019-06-11 22:27:09 +02:00
|
|
|
std::vector<_range_fuzz_type_entry<_Type, _Args...>> m_map;
|
2019-05-03 00:29:04 +02:00
|
|
|
std::function<_Type(_Type, std::function<void(_Type)>)> m_pfnOnFuzzedValueFromMap;
|
|
|
|
std::tuple<_Args...> m_tArgs;
|
|
|
|
|
|
|
|
_Type CallFuzzMapFunction(
|
|
|
|
std::function<_Type(_Type, _Args...)> pfnFuzz,
|
|
|
|
_Type t,
|
|
|
|
std::tuple<_Args...>& tup)
|
|
|
|
{
|
2019-06-11 22:27:09 +02:00
|
|
|
return CallFuzzMapFunction(pfnFuzz, t, tup, variadic::gen_seq<sizeof...(_Args)>{});
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// To support sub classes ability to realloc fuzzed values,
|
|
|
|
// the m_pfnOnFuzzedValueFromMap will be invoked whenever a fuzz map
|
|
|
|
// entry is selected. When not overridden, the default behavior is to
|
2019-06-11 22:27:09 +02:00
|
|
|
// set this classes value to the fuzzed value returned from the
|
2019-05-03 00:29:04 +02:00
|
|
|
// associated fuzzing routine. For an example that alters this behavior
|
|
|
|
// take a look at the CFuzzLpwstr class.
|
|
|
|
__inline virtual _Type GetValueFromMap()
|
|
|
|
{
|
|
|
|
if (!m_fFuzzed)
|
|
|
|
{
|
|
|
|
m_fFuzzed = TRUE;
|
|
|
|
m_t = m_tInit;
|
|
|
|
WORD wRandom = CFuzzChance::GetRandom<WORD>(100);
|
2019-06-11 22:27:09 +02:00
|
|
|
for (auto& r : m_map)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
if (r.range.iLow <= wRandom && wRandom < r.range.iHigh)
|
|
|
|
{
|
|
|
|
m_t = m_pfnOnFuzzedValueFromMap(CallFuzzMapFunction(r.fte.pfnFuzz, m_tInit, m_tArgs), r.fte.pfnDealloc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_t;
|
|
|
|
}
|
2019-06-11 22:27:09 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
private:
|
2019-06-11 22:27:09 +02:00
|
|
|
template<int... Is>
|
2019-05-03 00:29:04 +02:00
|
|
|
_Type CallFuzzMapFunction(
|
|
|
|
std::function<_Type(_Type, _Args...)> pfnFuzz,
|
|
|
|
_Type t,
|
|
|
|
std::tuple<_Args...>& tup,
|
|
|
|
variadic::index<Is...>)
|
|
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(tup); // Compiler gets confused by the expansion of tup below.
|
|
|
|
return pfnFuzz(t, std::get<Is>(tup)...);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// The CFuzzTypePtr class provides all the same functionality as the
|
2019-06-11 22:27:09 +02:00
|
|
|
// base CFuzzType class, but also provides an additional operator
|
2019-05-03 00:29:04 +02:00
|
|
|
// override for ->. This allows pointers to be wrapped by this class
|
|
|
|
// to be seamlessly used in the calling codebase. Note that correct
|
|
|
|
// fuzzing behavior is entirely dependent on the design of the fuzzing
|
|
|
|
// map, this class is not intended to fuzz actual pointer values.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type, typename... _Args>
|
|
|
|
class CFuzzTypePtr : public CFuzzType<_Type, _Args...>
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
// Note that _Type is expected to be a pointer type (thus making
|
|
|
|
// the operator override of -> make sense). It is the callers
|
|
|
|
// responsibility to set the type appropriately.
|
|
|
|
CFuzzTypePtr(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfte) const _fuzz_type_entry<_Type>* rgfte,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfte,
|
|
|
|
__in _Type pt,
|
|
|
|
__in _Args&&... args) :
|
2019-06-11 22:27:09 +02:00
|
|
|
CFuzzType(rgfte, cfte, pt, std::forward<_Args>(args)...)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
virtual ~CFuzzTypePtr() {}
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
_Type operator->() const throw()
|
|
|
|
{
|
2021-11-25 00:28:27 +01:00
|
|
|
return (this->m_fFuzzed) ? this->m_t : CFuzzType<_Type, _Args...>::m_tInit;
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// This operator makes it possible to invoke the fuzzing map
|
2019-06-11 22:27:09 +02:00
|
|
|
// by calling this class like a parameterless function. This is
|
2019-05-03 00:29:04 +02:00
|
|
|
// used to support the __make_untrusted call below. Note that once
|
|
|
|
// the fuzzing map is invoked, all future access of the pointer
|
|
|
|
// members will be pointed to potentially fuzzed data (as per
|
|
|
|
// the logic of the fuzz map).
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline void operator()() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2021-11-25 00:28:27 +01:00
|
|
|
CFuzzType<_Type, _Args...>::GetValueFromMap();
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// The CFuzzLpwstr class extends the CFuzzType class in order to
|
|
|
|
// provide the ability to realloc fuzzed strings. This is important
|
|
|
|
// because it might be desirable to grow or shrink a fuzzed string
|
|
|
|
// based upon the scenario. Because reallocation can occur, this
|
|
|
|
// class needs to maintain similar logic to the CFuzzArray class for
|
|
|
|
// transferring ownership of buffers. Similarly, if reallocation
|
|
|
|
// is allowed, _Alloc needs to match the appropriate allocation
|
|
|
|
// method used by the calling code. Please see CFuzzArray documentation
|
|
|
|
// for more details.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<class _Alloc, typename _Type, typename... _Args>
|
|
|
|
class CFuzzString : public CFuzzType<_Type*, _Args...>
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
CFuzzString(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfte) const _fuzz_type_entry<_Type*, _Args...>* rgfte,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfte,
|
2019-06-11 22:27:09 +02:00
|
|
|
__in _Type* psz,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in _Args... args) :
|
2019-06-11 22:27:09 +02:00
|
|
|
CFuzzType(rgfte, cfte, psz, std::forward<_Args>(args)...)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
OnFuzzedValueFromMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~CFuzzString()
|
|
|
|
{
|
|
|
|
FreeFuzzedString();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Provide operator overloading to allow this class to be
|
|
|
|
// initialized across function calls that would allocate
|
|
|
|
// a string. It is assumed that if initialization occurs
|
|
|
|
// via this method and then reallocation occurs, it will
|
|
|
|
// be necessary to transfer ownership of who frees the
|
|
|
|
// appropriate buffer.
|
|
|
|
// For example:
|
|
|
|
// __untrusted_lpwstr pwsz =
|
|
|
|
// __untrusted_lpwstr_init<LPWSTR>(FUZZ_MAP(...), nullptr);
|
|
|
|
// AllocateString(&pwsz);
|
|
|
|
// ...use pwsz to invoke fuzzing map...
|
|
|
|
// CoTaskMemFree(pwsz); // If reallocation occurs,
|
|
|
|
// // using pwsz will provide the
|
|
|
|
// // fuzzed string. This means
|
|
|
|
// // pwsz is responsible for freeing
|
|
|
|
// // the original allocation.
|
2019-06-11 22:27:09 +02:00
|
|
|
__inline virtual _Type** operator&() throw()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
m_ftEffectiveTraits |= TRAIT_TRANSFER_ALLOCATION;
|
2021-11-25 00:28:27 +01:00
|
|
|
return (this->m_fFuzzed) ? &(this->m_t) : &CFuzzType<_Type, _Args...>::m_tInit;
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
2019-06-11 22:27:09 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
private:
|
2019-06-11 22:27:09 +02:00
|
|
|
_Type* m_pszFuzzed;
|
2019-05-03 00:29:04 +02:00
|
|
|
FuzzTraits m_ftEffectiveTraits;
|
|
|
|
|
|
|
|
// Since reallocation could occur that is dependent on matching the
|
2019-06-11 22:27:09 +02:00
|
|
|
// allocation routines of the calling code, we want to ensure we
|
2019-05-03 00:29:04 +02:00
|
|
|
// allocate using the correct allocator specified by _Alloc. However,
|
|
|
|
// the allocation routines in the fuzzing map could differ, therefore
|
|
|
|
// we copy the fuzzed string as appropriate and use the specified
|
|
|
|
// dealloc function in the fuzz map entry to delete the fuzzed string
|
|
|
|
// created by the fuzz map entry. Slightly inefficient, but safer
|
2019-06-11 22:27:09 +02:00
|
|
|
// and supports a wider variety of scenarios.
|
2019-05-03 00:29:04 +02:00
|
|
|
void OnFuzzedValueFromMap()
|
|
|
|
{
|
|
|
|
m_pszFuzzed = nullptr;
|
2019-08-07 19:58:53 +02:00
|
|
|
m_ftEffectiveTraits = this->m_traits;
|
|
|
|
this->m_pfnOnFuzzedValueFromMap = [&](_Type* psz, std::function<void(_Type*)> dealloc) {
|
2019-05-03 00:29:04 +02:00
|
|
|
FreeFuzzedString();
|
2019-06-11 22:27:09 +02:00
|
|
|
_Type* pszFuzzed = psz;
|
2019-08-07 19:58:53 +02:00
|
|
|
if (psz && psz != this->m_tInit)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
size_t cb = (sizeof(_Type) == sizeof(char)) ?
|
2019-06-11 22:27:09 +02:00
|
|
|
(strlen(reinterpret_cast<LPSTR>(psz)) + 1) * sizeof(char) :
|
|
|
|
(wcslen(reinterpret_cast<LPWSTR>(psz)) + 1) * sizeof(WCHAR);
|
2019-05-03 00:29:04 +02:00
|
|
|
m_pszFuzzed = reinterpret_cast<_Type*>(_Alloc::Allocate(cb));
|
|
|
|
if (m_pszFuzzed)
|
|
|
|
{
|
|
|
|
(sizeof(_Type) == sizeof(char)) ?
|
|
|
|
StringCbCopyA(reinterpret_cast<LPSTR>(m_pszFuzzed), cb, reinterpret_cast<LPCSTR>(psz)) :
|
|
|
|
StringCbCopyW(reinterpret_cast<LPWSTR>(m_pszFuzzed), cb, reinterpret_cast<LPCWSTR>(psz));
|
|
|
|
pszFuzzed = m_pszFuzzed;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dealloc)
|
|
|
|
{
|
|
|
|
dealloc(psz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pszFuzzed;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeFuzzedString()
|
|
|
|
{
|
|
|
|
if (m_pszFuzzed)
|
|
|
|
{
|
|
|
|
// See comments about explaining when we transfer
|
|
|
|
// allocation and deallocation responsibilities.
|
|
|
|
if (m_ftEffectiveTraits & TRAIT_TRANSFER_ALLOCATION)
|
|
|
|
{
|
2019-08-07 19:58:53 +02:00
|
|
|
_Alloc::Free(this->m_tInit);
|
|
|
|
this->m_tInit = nullptr;
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_Alloc::Free(m_pszFuzzed);
|
|
|
|
m_pszFuzzed = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
// The CFuzzFlags class extends the CFuzzType base class, but
|
2019-05-03 00:29:04 +02:00
|
|
|
// operates slightly differently than other fuzz class implementations.
|
|
|
|
// The intended usage of this class is when dealing with bit flags,
|
|
|
|
// where covering the range of possible bit flag combinations would be
|
|
|
|
// very tedious for the fuzz map designer. To aid in this scenario,
|
|
|
|
// the fuzz map entries are evaluated on a per flag basis, meaning the
|
|
|
|
// chance of inserting that flag is dependent on the percentage value.
|
|
|
|
// For example:
|
|
|
|
// In the below fuzz map, CFuzzFlags will interpret this to mean
|
|
|
|
// apply STARTF_FORCEONFEEDBACK 10% of the time, together with
|
|
|
|
// STARTF_FORCEOFFFEEDBACK 2% of the time, together with
|
|
|
|
// STARTF_PREVENTPINNING %1 of the time, etc.
|
|
|
|
//
|
|
|
|
// _fuzz_type_entry<DWORD> _fuzz_dwFlags_map[] =
|
|
|
|
// {
|
|
|
|
// { 10, [] (DWORD) { return STARTF_FORCEONFEEDBACK; } },
|
|
|
|
// { 2, [] (DWORD) { return STARTF_FORCEOFFFEEDBACK; } },
|
|
|
|
// { 1, [] (DWORD) { return STARTF_PREVENTPINNING; } },
|
|
|
|
// { 50, [] (DWORD) { return STARTF_RUNFULLSCREEN; } },
|
|
|
|
// };
|
|
|
|
//
|
|
|
|
// Also note that this class should specifically not have the
|
2019-06-11 22:27:09 +02:00
|
|
|
// TRAIT_THROW_ON_INIT_FAILURE trait, as it is expected that the
|
2019-05-03 00:29:04 +02:00
|
|
|
// percentages will total more than 100% when added together.
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename _Type, typename... _Args>
|
|
|
|
class CFuzzFlags : public CFuzzType<_Type, _Args...>
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
CFuzzFlags(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfte) const _fuzz_type_entry<_Type>* rgfte,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfte,
|
|
|
|
__in _Type flags,
|
|
|
|
__in _Args&&... args) :
|
2019-06-11 22:27:09 +02:00
|
|
|
CFuzzType(rgfte, cfte, flags, std::forward<_Args>(args)...)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~CFuzzFlags()
|
|
|
|
{
|
|
|
|
}
|
2019-06-11 22:27:09 +02:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
protected:
|
|
|
|
__inline virtual _Type GetValueFromMap()
|
|
|
|
{
|
2019-08-07 19:58:53 +02:00
|
|
|
if (!this->m_fFuzzed)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2019-08-07 19:58:53 +02:00
|
|
|
this->m_t = 0;
|
|
|
|
this->m_fFuzzed = TRUE;
|
|
|
|
for (auto& r : this->m_map)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
// Generate a new random value during each map entry
|
2019-06-11 22:27:09 +02:00
|
|
|
// and use it to evaluate if each individual fuzz map
|
2019-05-03 00:29:04 +02:00
|
|
|
// entry should be applied.
|
|
|
|
WORD wRandom = CFuzzChance::GetRandom<WORD>(100);
|
|
|
|
|
|
|
|
// Translate percentages to allow for each flag to be considered
|
|
|
|
// for inclusion independently.
|
|
|
|
int iHigh = 100;
|
|
|
|
int iLow = iHigh - (r.range.iHigh - r.range.iLow);
|
|
|
|
if (iLow <= wRandom && wRandom < iHigh)
|
|
|
|
{
|
2021-11-25 00:28:27 +01:00
|
|
|
this->m_t |= CallFuzzMapFunction(r.fte.pfnFuzz, this->m_tInit, CFuzzType<_Type, _Args...>::m_tArgs);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 19:58:53 +02:00
|
|
|
return this->m_t;
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// To make using these classes a no-opt if fuzzing is not intended to
|
|
|
|
// be applied, the following set of functions and defines operate
|
|
|
|
// differently if __GENERATE_DIRECTED_FUZZING is defined. If defined,
|
2019-06-11 22:27:09 +02:00
|
|
|
// these wrappers use the correct fuzz classes and initialize these
|
2019-05-03 00:29:04 +02:00
|
|
|
// classes with the appropriate map specified by the caller. If not
|
2019-06-11 22:27:09 +02:00
|
|
|
// defined, essentially the use of these classes disappear and the
|
2019-05-03 00:29:04 +02:00
|
|
|
// remaining functions are optimized away by the compiler. When
|
|
|
|
// applied appropriately, not turning on fuzzing leaves no performance
|
|
|
|
// impact, no size footprint, and no leakage of information into the
|
|
|
|
// symbols.
|
|
|
|
#ifdef __GENERATE_DIRECTED_FUZZING
|
|
|
|
#define FUZZ_ARRAY_START_STATIC(name, type, size, ...) static const fuzz::_fuzz_array_entry<type, size, __VA_ARGS__> name[] = {
|
|
|
|
#define FUZZ_ARRAY_START(name, type, size, ...) const fuzz::_fuzz_array_entry<type, size, __VA_ARGS__> name[] = {
|
2019-06-11 22:27:09 +02:00
|
|
|
#define FUZZ_ARRAY_END() \
|
|
|
|
} \
|
|
|
|
;
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
#define FUZZ_TYPE_START_STATIC(name, type, ...) static const fuzz::_fuzz_type_entry<type, __VA_ARGS__> name[] = {
|
|
|
|
#define FUZZ_TYPE_START(name, type, ...) const fuzz::_fuzz_type_entry<type, __VA_ARGS__> name[] = {
|
2019-06-11 22:27:09 +02:00
|
|
|
#define FUZZ_TYPE_END() \
|
|
|
|
} \
|
|
|
|
;
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
#define FUZZ_MAP_ENTRY_ALLOC(i, pfnAlloc, pfnDelete) { i, pfnAlloc, pfnDelete },
|
|
|
|
#define FUZZ_MAP_ENTRY(i, pfnAlloc) { i, pfnAlloc },
|
|
|
|
|
|
|
|
#define FUZZ_MAP(x) x, ARRAYSIZE(x)
|
|
|
|
|
|
|
|
#define __untrusted_t(type, ...) fuzz::CFuzzType<type, __VA_ARGS__>
|
|
|
|
#define __untrusted_lpwstr_t(...) fuzz::CFuzzString<__FUZZING_ALLOCATOR, WCHAR, __VA_ARGS__>
|
|
|
|
#define __untrusted_lpwstr fuzz::CFuzzString<__FUZZING_ALLOCATOR, WCHAR>
|
|
|
|
#define __untrusted_lpstr_t(...) fuzz::CFuzzString<__FUZZING_ALLOCATOR, CHAR, __VA_ARGS__>
|
|
|
|
#define __untrusted_lpstr fuzz::CFuzzString<__FUZZING_ALLOCATOR, CHAR>
|
|
|
|
#define __untrusted_ptr(ptr, ...) fuzz::CFuzzTypePtr<ptr, __VA_ARGS__>
|
|
|
|
#define __untrusted_array(ptr, size, ...) fuzz::CFuzzArray<__FUZZING_ALLOCATOR, ptr, size, __VA_ARGS__>
|
|
|
|
#define __untrusted_array_size(ptr, size, ...) fuzz::CFuzzArraySize<ptr, size, __VA_ARGS__>
|
|
|
|
|
|
|
|
template<typename _Type, typename... _Args>
|
|
|
|
static fuzz::CFuzzType<_Type, _Args...> __untrusted_init(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfte) const fuzz::_fuzz_type_entry<_Type, _Args...>* rgfte,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfte,
|
|
|
|
__in _Type t,
|
|
|
|
__in _Args&&... args)
|
|
|
|
{
|
|
|
|
return fuzz::CFuzzType<_Type, _Args...>(rgfte, cfte, t, std::forward<_Args>(args)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename... _Args>
|
|
|
|
static fuzz::CFuzzString<__FUZZING_ALLOCATOR, WCHAR, _Args...> __untrusted_lpwstr_init(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfte) const fuzz::_fuzz_type_entry<LPWSTR, _Args...>* rgfte,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfte,
|
|
|
|
__in LPWSTR pwsz,
|
|
|
|
__in _Args&&... args)
|
|
|
|
{
|
|
|
|
return fuzz::CFuzzString<__FUZZING_ALLOCATOR, WCHAR, _Args...>(rgfte, cfte, pwsz, std::forward<_Args>(args)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename... _Args>
|
|
|
|
static fuzz::CFuzzString<__FUZZING_ALLOCATOR, CHAR, _Args...> __untrusted_lpstr_init(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfte) const fuzz::_fuzz_type_entry<LPSTR, _Args...>* rgfte,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfte,
|
|
|
|
__in LPSTR psz,
|
|
|
|
__in _Args&&... args)
|
|
|
|
{
|
|
|
|
return fuzz::CFuzzString<__FUZZING_ALLOCATOR, CHAR, _Args...>(rgfte, cfte, psz, std::forward<_Args>(args)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Type1, typename _Type2, typename... _Args>
|
|
|
|
static fuzz::CFuzzArray<__FUZZING_ALLOCATOR, _Type1, _Type2, _Args...> __untrusted_array_init(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_ecount(cfae) const fuzz::_fuzz_array_entry<_Type1, _Type2, _Args...>* rgfae,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG cfae,
|
2019-06-11 22:27:09 +02:00
|
|
|
__in _Type1* pt,
|
|
|
|
__in fuzz::CFuzzArraySize<_Type1, _Type2, _Args...>& rfas,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in _Args&&... args)
|
|
|
|
{
|
|
|
|
return fuzz::CFuzzArray<__FUZZING_ALLOCATOR, _Type1, _Type2, _Args...>(rgfae, cfae, pt, rfas, std::forward<_Args>(args)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Type1, typename _Type2, typename... _Args>
|
2019-06-11 22:27:09 +02:00
|
|
|
static fuzz::CFuzzArraySize<_Type1, _Type2, _Args...> __untrusted_array_size_init(__inout _Type2& t2)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return fuzz::CFuzzArraySize<_Type1, _Type2, _Args...>(t2);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Type, typename... _Args>
|
2019-06-11 22:27:09 +02:00
|
|
|
static void __make_untrusted_ptr(__in fuzz::CFuzzTypePtr<_Type, _Args...>& rftp)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
rftp();
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define FUZZ_ARRAY_START_STATIC(name, type, size, ...)
|
|
|
|
#define FUZZ_ARRAY_START(name, type, size, ...)
|
|
|
|
#define FUZZ_ARRAY_END()
|
|
|
|
|
|
|
|
#define FUZZ_TYPE_START_STATIC(name, type, ...)
|
|
|
|
#define FUZZ_TYPE_START(name, type, ...)
|
|
|
|
#define FUZZ_TYPE_END()
|
|
|
|
|
|
|
|
#define FUZZ_MAP_ENTRY_ALLOC(i, pfnAlloc, pfnDelete)
|
|
|
|
#define FUZZ_MAP_ENTRY(i, pfnAlloc)
|
|
|
|
|
|
|
|
#define FUZZ_MAP(x) nullptr, 0
|
|
|
|
|
|
|
|
#define __untrusted_t(type, ...) type
|
|
|
|
#define __untrusted_lpwstr_t(...) LPWSTR
|
|
|
|
#define __untrusted_lpwstr LPWSTR
|
|
|
|
#define __untrusted_lpstr_t(...) LPSTR
|
|
|
|
#define __untrusted_lpstr LPSTR
|
|
|
|
#define __untrusted_ptr(type, ...) type
|
|
|
|
#define __untrusted_array(ptr, size, ...) ptr*
|
|
|
|
#define __untrusted_array_size(ptr, size, ...) size
|
|
|
|
|
|
|
|
template<typename _Type, typename... _Args>
|
|
|
|
static __forceinline _Type __untrusted_init(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_opt void*,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG,
|
|
|
|
__in _Type t,
|
|
|
|
__in _Args&&...)
|
|
|
|
{
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
static __forceinline LPWSTR __untrusted_lpwstr_init(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_opt void*,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG,
|
|
|
|
__in LPWSTR pwsz,
|
|
|
|
__in _Args&&...)
|
|
|
|
{
|
|
|
|
return pwsz;
|
|
|
|
}
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
template<typename... _Args>
|
2019-05-03 00:29:04 +02:00
|
|
|
static __forceinline LPSTR __untrusted_lpstr_init(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_opt void*,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG,
|
|
|
|
__in LPSTR psz,
|
|
|
|
__in _Args&&...)
|
|
|
|
{
|
|
|
|
return psz;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Type1, typename _Type2, typename... _Args>
|
|
|
|
static __forceinline _Type1* __untrusted_array_init(
|
2019-06-11 22:27:09 +02:00
|
|
|
__in_opt void*,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in ULONG,
|
2019-06-11 22:27:09 +02:00
|
|
|
__in _Type1* pt,
|
2019-05-03 00:29:04 +02:00
|
|
|
__in _Type2,
|
|
|
|
__in _Args&&...)
|
|
|
|
{
|
|
|
|
return pt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Type1, typename _Type2, typename... _Args>
|
|
|
|
static _Type2 __untrusted_array_size_init(_Type2 t2)
|
|
|
|
{
|
|
|
|
return t2;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename _Type, typename... _Args>
|
|
|
|
static __forceinline void __make_untrusted_ptr(__in _Type&)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|