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