1 // Copyright 2019 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include <cstddef>
16 #include <cstdint>
17 #include <cstring>
18 #include <vector>
19
20 #include "fuzz.h"
21 #include "pw_fuzzer/asan_interface.h"
22 #include "pw_fuzzer/fuzzed_data_provider.h"
23 #include "pw_protobuf/encoder.h"
24 #include "pw_span/span.h"
25
26 namespace pw::protobuf::fuzz {
27 namespace {
28
29 // TODO: b/235289495 - Move this to pw_fuzzer/fuzzed_data_provider.h
30
31 // Uses the given |provider| to pick and return a number between 0 and the
32 // maximum numbers of T that can be generated from the remaining input data.
33 template <typename T>
ConsumeSize(FuzzedDataProvider & provider)34 size_t ConsumeSize(FuzzedDataProvider& provider) {
35 size_t max = provider.remaining_bytes() / sizeof(T);
36 return provider.ConsumeIntegralInRange<size_t>(0, max);
37 }
38
39 // Uses the given |provider| to generate several instances of T, store them in
40 // |data|, and then return a span to them. It is the caller's responsbility
41 // to ensure |data| remains in scope as long as the returned span.
42 template <typename T>
ConsumeSpan(FuzzedDataProvider & provider,std::vector<T> * data)43 span<const T> ConsumeSpan(FuzzedDataProvider& provider, std::vector<T>* data) {
44 size_t num = ConsumeSize<T>(provider);
45 size_t off = data->size();
46 if (num == 0) {
47 return span<const T>();
48 }
49
50 data->reserve(off + num);
51 for (size_t i = 0; i < num; ++i) {
52 if constexpr (std::is_floating_point<T>::value) {
53 data->push_back(provider.ConsumeFloatingPoint<T>());
54 } else {
55 data->push_back(provider.ConsumeIntegral<T>());
56 }
57 }
58 return span(&((*data)[off]), num);
59 }
60
61 // Uses the given |provider| to generate a string, store it in |data|, and
62 // return a C-style representation. It is the caller's responsbility to
63 // ensure |data| remains in scope as long as the returned char*.
ConsumeString(FuzzedDataProvider & provider,std::vector<std::string> * data)64 const char* ConsumeString(FuzzedDataProvider& provider,
65 std::vector<std::string>* data) {
66 size_t off = data->size();
67 // OSS-Fuzz's clang doesn't have the zero-parameter version of
68 // ConsumeRandomLengthString yet.
69 size_t max_length = std::numeric_limits<size_t>::max();
70 data->push_back(provider.ConsumeRandomLengthString(max_length));
71 return (*data)[off].c_str();
72 }
73
74 // Uses the given |provider| to generate non-arithmetic bytes, store them in
75 // |data|, and return a span to them. It is the caller's responsbility to
76 // ensure |data| remains in scope as long as the returned span.
ConsumeBytes(FuzzedDataProvider & provider,std::vector<std::byte> * data)77 span<const std::byte> ConsumeBytes(FuzzedDataProvider& provider,
78 std::vector<std::byte>* data) {
79 size_t num = ConsumeSize<std::byte>(provider);
80 auto added = provider.ConsumeBytes<std::byte>(num);
81 size_t off = data->size();
82 num = added.size();
83 data->insert(data->end(), added.begin(), added.end());
84 // It's possible nothing was added, and the vector was empty to begin with.
85 if (data->empty()) {
86 return span<const std::byte>();
87 }
88 return span(&((*data)[off]), num);
89 }
90
RecursiveFuzzedEncode(FuzzedDataProvider & provider,StreamEncoder & encoder,uint32_t depth=0)91 void RecursiveFuzzedEncode(FuzzedDataProvider& provider,
92 StreamEncoder& encoder,
93 uint32_t depth = 0) {
94 constexpr size_t kMaxDepth = 256;
95 if (depth > kMaxDepth) {
96 return;
97 }
98
99 // Storage for generated spans
100 std::vector<uint32_t> u32s;
101 std::vector<uint64_t> u64s;
102 std::vector<int32_t> s32s;
103 std::vector<int64_t> s64s;
104 std::vector<float> floats;
105 std::vector<double> doubles;
106 std::vector<std::string> strings;
107 std::vector<std::byte> bytes;
108
109 // Consume the fuzzing input, using it to generate a sequence of fields to
110 // encode. Both the uint32_t field IDs and the fields values are generated.
111 // Don't try to detect errors, ensures pushes and pops are balanced, or
112 // otherwise hold the interface correctly. Instead, fuzz the widest possbile
113 // set of inputs to the encoder to ensure it doesn't misbehave.
114 while (provider.remaining_bytes() != 0) {
115 switch (provider.ConsumeEnum<FieldType>()) {
116 case kUint32:
117 encoder
118 .WriteUint32(provider.ConsumeIntegral<uint32_t>(),
119 provider.ConsumeIntegral<uint32_t>())
120 .IgnoreError();
121 break;
122 case kPackedUint32:
123 encoder
124 .WritePackedUint32(provider.ConsumeIntegral<uint32_t>(),
125 ConsumeSpan<uint32_t>(provider, &u32s))
126 .IgnoreError();
127 break;
128 case kUint64:
129 encoder
130 .WriteUint64(provider.ConsumeIntegral<uint32_t>(),
131 provider.ConsumeIntegral<uint64_t>())
132 .IgnoreError();
133 break;
134 case kPackedUint64:
135 encoder
136 .WritePackedUint64(provider.ConsumeIntegral<uint32_t>(),
137 ConsumeSpan<uint64_t>(provider, &u64s))
138 .IgnoreError();
139 break;
140 case kInt32:
141 encoder
142 .WriteInt32(provider.ConsumeIntegral<uint32_t>(),
143 provider.ConsumeIntegral<int32_t>())
144 .IgnoreError();
145 break;
146 case kPackedInt32:
147 encoder
148 .WritePackedInt32(provider.ConsumeIntegral<uint32_t>(),
149 ConsumeSpan<int32_t>(provider, &s32s))
150 .IgnoreError();
151 break;
152 case kInt64:
153 encoder
154 .WriteInt64(provider.ConsumeIntegral<uint32_t>(),
155 provider.ConsumeIntegral<int64_t>())
156 .IgnoreError();
157 break;
158 case kPackedInt64:
159 encoder
160 .WritePackedInt64(provider.ConsumeIntegral<uint32_t>(),
161 ConsumeSpan<int64_t>(provider, &s64s))
162 .IgnoreError();
163 break;
164 case kSint32:
165 encoder
166 .WriteSint32(provider.ConsumeIntegral<uint32_t>(),
167 provider.ConsumeIntegral<int32_t>())
168 .IgnoreError();
169 break;
170 case kPackedSint32:
171 encoder
172 .WritePackedSint32(provider.ConsumeIntegral<uint32_t>(),
173 ConsumeSpan<int32_t>(provider, &s32s))
174 .IgnoreError();
175 break;
176 case kSint64:
177 encoder
178 .WriteSint64(provider.ConsumeIntegral<uint32_t>(),
179 provider.ConsumeIntegral<int64_t>())
180 .IgnoreError();
181 break;
182 case kPackedSint64:
183 encoder
184 .WritePackedSint64(provider.ConsumeIntegral<uint32_t>(),
185 ConsumeSpan<int64_t>(provider, &s64s))
186 .IgnoreError();
187 break;
188 case kBool:
189 encoder
190 .WriteBool(provider.ConsumeIntegral<uint32_t>(),
191 provider.ConsumeBool())
192 .IgnoreError();
193 break;
194 case kFixed32:
195 encoder
196 .WriteFixed32(provider.ConsumeIntegral<uint32_t>(),
197 provider.ConsumeIntegral<uint32_t>())
198 .IgnoreError();
199 break;
200 case kPackedFixed32:
201 encoder
202 .WritePackedFixed32(provider.ConsumeIntegral<uint32_t>(),
203 ConsumeSpan<uint32_t>(provider, &u32s))
204 .IgnoreError();
205 break;
206 case kFixed64:
207 encoder
208 .WriteFixed64(provider.ConsumeIntegral<uint32_t>(),
209 provider.ConsumeIntegral<uint64_t>())
210 .IgnoreError();
211 break;
212 case kPackedFixed64:
213 encoder
214 .WritePackedFixed64(provider.ConsumeIntegral<uint32_t>(),
215 ConsumeSpan<uint64_t>(provider, &u64s))
216 .IgnoreError();
217 break;
218 case kSfixed32:
219 encoder
220 .WriteSfixed32(provider.ConsumeIntegral<uint32_t>(),
221 provider.ConsumeIntegral<int32_t>())
222 .IgnoreError();
223 break;
224 case kPackedSfixed32:
225 encoder
226 .WritePackedSfixed32(provider.ConsumeIntegral<uint32_t>(),
227 ConsumeSpan<int32_t>(provider, &s32s))
228 .IgnoreError();
229 break;
230 case kSfixed64:
231 encoder
232 .WriteSfixed64(provider.ConsumeIntegral<uint32_t>(),
233 provider.ConsumeIntegral<int64_t>())
234 .IgnoreError();
235 break;
236 case kPackedSfixed64:
237 encoder
238 .WritePackedSfixed64(provider.ConsumeIntegral<uint32_t>(),
239 ConsumeSpan<int64_t>(provider, &s64s))
240 .IgnoreError();
241 break;
242 case kFloat:
243 encoder
244 .WriteFloat(provider.ConsumeIntegral<uint32_t>(),
245 provider.ConsumeFloatingPoint<float>())
246 .IgnoreError();
247 break;
248 case kPackedFloat:
249 encoder
250 .WritePackedFloat(provider.ConsumeIntegral<uint32_t>(),
251 ConsumeSpan<float>(provider, &floats))
252 .IgnoreError();
253 break;
254 case kDouble:
255 encoder
256 .WriteDouble(provider.ConsumeIntegral<uint32_t>(),
257 provider.ConsumeFloatingPoint<double>())
258 .IgnoreError();
259 break;
260 case kPackedDouble:
261 encoder
262 .WritePackedDouble(provider.ConsumeIntegral<uint32_t>(),
263 ConsumeSpan<double>(provider, &doubles))
264 .IgnoreError();
265 break;
266 case kBytes:
267 encoder
268 .WriteBytes(provider.ConsumeIntegral<uint32_t>(),
269 ConsumeBytes(provider, &bytes))
270 .IgnoreError();
271 break;
272 case kString:
273 encoder
274 .WriteString(provider.ConsumeIntegral<uint32_t>(),
275 ConsumeString(provider, &strings))
276 .IgnoreError();
277 break;
278 case kPush: {
279 // Special "field". The marks the start of a nested message.
280 StreamEncoder nested_encoder =
281 encoder.GetNestedEncoder(provider.ConsumeIntegral<uint32_t>());
282 RecursiveFuzzedEncode(provider, nested_encoder, depth + 1);
283 break;
284 }
285 case kPop:
286 if (depth > 0) {
287 // Special "field". The marks the end of a nested message.
288 return;
289 }
290 }
291 }
292 }
293
TestOneInput(FuzzedDataProvider & provider)294 void TestOneInput(FuzzedDataProvider& provider) {
295 static std::byte buffer[65536];
296
297 // Pick a subset of the buffer that the fuzzer is allowed to use, and poison
298 // the rest.
299 size_t unpoisoned_length =
300 provider.ConsumeIntegralInRange<size_t>(0, sizeof(buffer));
301 ByteSpan unpoisoned(buffer, unpoisoned_length);
302 void* poisoned = &buffer[unpoisoned_length];
303 size_t poisoned_length = sizeof(buffer) - unpoisoned_length;
304 ASAN_POISON_MEMORY_REGION(poisoned, poisoned_length);
305
306 pw::protobuf::MemoryEncoder encoder(unpoisoned);
307 RecursiveFuzzedEncode(provider, encoder);
308
309 // Don't forget to unpoison for the next iteration!
310 ASAN_UNPOISON_MEMORY_REGION(poisoned, poisoned_length);
311 }
312
313 } // namespace
314 } // namespace pw::protobuf::fuzz
315
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)316 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
317 FuzzedDataProvider provider(data, size);
318 pw::protobuf::fuzz::TestOneInput(provider);
319 return 0;
320 }
321