1 /* Copyright 2019 Guido Vranken
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject
9 * to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be
12 * included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #pragma once
25
26 #include <fuzzing/exception.hpp>
27 #include <fuzzing/types.hpp>
28 #include <cstddef>
29 #include <cstdint>
30 #include <cstdlib>
31 #include <cstring>
32 #include <string>
33 #include <vector>
34
35 namespace fuzzing {
36 namespace datasource {
37
38 class Base
39 {
40 protected:
41 virtual std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) = 0;
42 public:
43 Base(void) = default;
44 virtual ~Base(void) = default;
45
46 template<class T> T Get(const uint64_t id = 0);
47 uint16_t GetChoice(const uint64_t id = 0);
48 std::vector<uint8_t> GetData(const uint64_t id, const size_t min = 0, const size_t max = 0);
49 template <class T> std::vector<T> GetVector(const uint64_t id = 0);
50
51 class OutOfData : public fuzzing::exception::FlowException {
52 public:
53 OutOfData() = default;
54 };
55
56 class DeserializationFailure : public fuzzing::exception::FlowException {
57 public:
58 DeserializationFailure() = default;
59 };
60 };
61
62 #ifndef FUZZING_HEADERS_NO_IMPL
Get(const uint64_t id)63 template<class T> T Base::Get(const uint64_t id)
64 {
65 T ret;
66 const auto v = get(sizeof(ret), sizeof(ret), id);
67 memcpy(&ret, v.data(), sizeof(ret));
68 return ret;
69 }
70
Get(const uint64_t id)71 template <> bool Base::Get<bool>(const uint64_t id)
72 {
73 uint8_t ret;
74 const auto v = get(sizeof(ret), sizeof(ret), id);
75 memcpy(&ret, v.data(), sizeof(ret));
76 return (ret % 2) ? true : false;
77 }
78
Get(const uint64_t id)79 template <> std::string Base::Get<std::string>(const uint64_t id)
80 {
81 auto data = GetData(id);
82 return std::string(data.data(), data.data() + data.size());
83 }
84
Get(const uint64_t id)85 template <> std::vector<std::string> Base::Get<std::vector<std::string>>(const uint64_t id)
86 {
87 std::vector<std::string> ret;
88 while ( true ) {
89 auto data = GetData(id);
90 ret.push_back( std::string(data.data(), data.data() + data.size()) );
91 if ( Get<bool>(id) == false ) {
92 break;
93 }
94 }
95 return ret;
96 }
97
GetChoice(const uint64_t id)98 uint16_t Base::GetChoice(const uint64_t id)
99 {
100 return Get<uint16_t>(id);
101 }
102
GetData(const uint64_t id,const size_t min,const size_t max)103 std::vector<uint8_t> Base::GetData(const uint64_t id, const size_t min, const size_t max)
104 {
105 return get(min, max, id);
106 }
107
108
Get(const uint64_t id)109 template <> types::String<> Base::Get<types::String<>>(const uint64_t id) {
110 const auto data = GetData(id);
111 types::String<> ret(data.data(), data.size());
112 return ret;
113 }
114
Get(const uint64_t id)115 template <> types::Data<> Base::Get<types::Data<>>(const uint64_t id) {
116 const auto data = GetData(id);
117 types::Data<> ret(data.data(), data.size());
118 return ret;
119 }
120
121 template <class T>
GetVector(const uint64_t id)122 std::vector<T> Base::GetVector(const uint64_t id) {
123 std::vector<T> ret;
124
125 while ( Get<bool>(id) == true ) {
126 ret.push_back( Get<T>(id) );
127 }
128
129 return ret;
130 }
131 #endif
132
133 class Datasource : public Base
134 {
135 private:
136 const uint8_t* data;
137 const size_t size;
138 size_t idx;
139 size_t left;
140 std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) override;
141
142 // Make copy constructor and assignment operator private.
Datasource(const Datasource &)143 Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {}
operator =(const Datasource &)144 Datasource& operator=(const Datasource &) { return *this; }
145 public:
146 Datasource(const uint8_t* _data, const size_t _size);
147 };
148
149 #ifndef FUZZING_HEADERS_NO_IMPL
Datasource(const uint8_t * _data,const size_t _size)150 Datasource::Datasource(const uint8_t* _data, const size_t _size) :
151 Base(), data(_data), size(_size), idx(0), left(size)
152 {
153 }
154
get(const size_t min,const size_t max,const uint64_t id)155 std::vector<uint8_t> Datasource::get(const size_t min, const size_t max, const uint64_t id) {
156 (void)id;
157
158 uint32_t getSize;
159 if ( left < sizeof(getSize) ) {
160 throw OutOfData();
161 }
162 memcpy(&getSize, data + idx, sizeof(getSize));
163 idx += sizeof(getSize);
164 left -= sizeof(getSize);
165
166 if ( getSize < min ) {
167 getSize = min;
168 }
169 if ( max && getSize > max ) {
170 getSize = max;
171 }
172
173 if ( left < getSize ) {
174 throw OutOfData();
175 }
176
177 std::vector<uint8_t> ret(getSize);
178
179 if ( getSize > 0 ) {
180 memcpy(ret.data(), data + idx, getSize);
181 }
182 idx += getSize;
183 left -= getSize;
184
185 return ret;
186 }
187 #endif
188
189 } /* namespace datasource */
190 } /* namespace fuzzing */
191