blob: 8eb7ed6c5a39e897667c4f5f60d55e41123527c2 [file] [log] [blame]
Aaron Green0ce7f412020-04-06 13:39:40 -07001// 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
Aaron Green0ce7f412020-04-06 13:39:40 -070015#include <cstddef>
16#include <cstdint>
17#include <cstring>
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070018#include <span>
Aaron Green0ce7f412020-04-06 13:39:40 -070019#include <vector>
20
Wyatt Heplerb93749b2021-05-11 09:38:22 -070021#include "pw_fuzzer/asan_interface.h"
22#include "pw_fuzzer/fuzzed_data_provider.h"
Aaron Green0ce7f412020-04-06 13:39:40 -070023#include "pw_protobuf/encoder.h"
Aaron Green0ce7f412020-04-06 13:39:40 -070024
25namespace {
26
27// Encodable values. The fuzzer will iteratively choose different field types to
28// generate and encode.
29enum FieldType : uint8_t {
30 kEncodeAndClear = 0,
31 kUint32,
32 kPackedUint32,
33 kUint64,
34 kPackedUint64,
35 kInt32,
36 kPackedInt32,
37 kInt64,
38 kPackedInt64,
39 kSint32,
40 kPackedSint32,
41 kSint64,
42 kPackedSint64,
43 kBool,
44 kFixed32,
45 kPackedFixed32,
46 kFixed64,
47 kPackedFixed64,
48 kSfixed32,
49 kPackedSfixed32,
50 kSfixed64,
51 kPackedSfixed64,
52 kFloat,
53 kPackedFloat,
54 kDouble,
55 kPackedDouble,
56 kBytes,
57 kString,
58 kPush,
59 kPop,
60 kMaxValue = kPop,
61};
62
63// TODO(pwbug/181): Move this to pw_fuzzer/fuzzed_data_provider.h
64
65// Uses the given |provider| to pick and return a number between 0 and the
66// maximum numbers of T that can be generated from the remaining input data.
67template <typename T>
68size_t ConsumeSize(FuzzedDataProvider* provider) {
69 size_t max = provider->remaining_bytes() / sizeof(T);
70 return provider->ConsumeIntegralInRange<size_t>(0, max);
71}
72
73// Uses the given |provider| to generate several instances of T, store them in
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070074// |data|, and then return a std::span to them. It is the caller's responsbility
75// to ensure |data| remains in scope as long as the returned std::span.
Aaron Green0ce7f412020-04-06 13:39:40 -070076template <typename T>
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070077std::span<const T> ConsumeSpan(FuzzedDataProvider* provider,
78 std::vector<T>* data) {
Aaron Green0ce7f412020-04-06 13:39:40 -070079 size_t num = ConsumeSize<T>(provider);
80 size_t off = data->size();
81 data->reserve(off + num);
82 for (size_t i = 0; i < num; ++i) {
83 if constexpr (std::is_floating_point<T>::value) {
84 data->push_back(provider->ConsumeFloatingPoint<T>());
85 } else {
86 data->push_back(provider->ConsumeIntegral<T>());
87 }
88 }
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070089 return std::span(&((*data)[off]), num);
Aaron Green0ce7f412020-04-06 13:39:40 -070090}
91
92// Uses the given |provider| to generate a string, store it in |data|, and
93// return a C-style representation. It is the caller's responsbility to
94// ensure |data| remains in scope as long as the returned char*.
95const char* ConsumeString(FuzzedDataProvider* provider,
96 std::vector<std::string>* data) {
97 size_t off = data->size();
Aaron Greenb3ae1dc2020-04-13 11:37:05 -070098 // OSS-Fuzz's clang doesn't have the zero-parameter version of
99 // ConsumeRandomLengthString yet.
100 size_t max_length = std::numeric_limits<size_t>::max();
101 data->push_back(provider->ConsumeRandomLengthString(max_length));
Aaron Green0ce7f412020-04-06 13:39:40 -0700102 return (*data)[off].c_str();
103}
104
105// Uses the given |provider| to generate non-arithmetic bytes, store them in
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700106// |data|, and return a std::span to them. It is the caller's responsbility to
107// ensure |data| remains in scope as long as the returned std::span.
108std::span<const std::byte> ConsumeBytes(FuzzedDataProvider* provider,
109 std::vector<std::byte>* data) {
Aaron Green0ce7f412020-04-06 13:39:40 -0700110 size_t num = ConsumeSize<std::byte>(provider);
111 auto added = provider->ConsumeBytes<std::byte>(num);
112 size_t off = data->size();
113 num = added.size();
114 data->insert(data->end(), added.begin(), added.end());
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700115 return std::span(&((*data)[off]), num);
Aaron Green0ce7f412020-04-06 13:39:40 -0700116}
117
118} // namespace
119
120extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
121 static std::byte buffer[65536];
122
123 FuzzedDataProvider provider(data, size);
124
125 // Pick a subset of the buffer that the fuzzer is allowed to use, and poison
126 // the rest.
127 size_t unpoisoned_length =
128 provider.ConsumeIntegralInRange<size_t>(0, sizeof(buffer));
Wyatt Heplere2cbadf2020-06-22 11:21:45 -0700129 std::span<std::byte> unpoisoned(buffer, unpoisoned_length);
Aaron Green0ce7f412020-04-06 13:39:40 -0700130 void* poisoned = &buffer[unpoisoned_length];
131 size_t poisoned_length = sizeof(buffer) - unpoisoned_length;
132 ASAN_POISON_MEMORY_REGION(poisoned, poisoned_length);
133
134 pw::protobuf::NestedEncoder encoder(unpoisoned);
Aaron Green0ce7f412020-04-06 13:39:40 -0700135
136 // Storage for generated spans
137 std::vector<uint32_t> u32s;
138 std::vector<uint64_t> u64s;
139 std::vector<int32_t> s32s;
140 std::vector<int64_t> s64s;
141 std::vector<float> floats;
142 std::vector<double> doubles;
143 std::vector<std::string> strings;
144 std::vector<std::byte> bytes;
145
146 // Consume the fuzzing input, using it to generate a sequence of fields to
147 // encode. Both the uint32_t field IDs and the fields values are generated.
148 // Don't try to detect errors, ensures pushes and pops are balanced, or
149 // otherwise hold the interface correctly. Instead, fuzz the widest possbile
150 // set of inputs to the encoder to ensure it doesn't misbehave.
151 while (provider.remaining_bytes() != 0) {
152 switch (provider.ConsumeEnum<FieldType>()) {
153 case kEncodeAndClear:
154 // Special "field". Encode all the fields so far and reset the encoder.
Wyatt Hepler86ec8822021-05-21 15:15:24 -0700155 encoder.Encode().IgnoreError();
Aaron Green0ce7f412020-04-06 13:39:40 -0700156 encoder.Clear();
157 break;
158 case kUint32:
159 encoder.WriteUint32(provider.ConsumeIntegral<uint32_t>(),
160 provider.ConsumeIntegral<uint32_t>());
161 break;
162 case kPackedUint32:
163 encoder.WritePackedUint32(provider.ConsumeIntegral<uint32_t>(),
164 ConsumeSpan<uint32_t>(&provider, &u32s));
165 break;
166 case kUint64:
167 encoder.WriteUint64(provider.ConsumeIntegral<uint32_t>(),
168 provider.ConsumeIntegral<uint64_t>());
169 break;
170 case kPackedUint64:
171 encoder.WritePackedUint64(provider.ConsumeIntegral<uint32_t>(),
172 ConsumeSpan<uint64_t>(&provider, &u64s));
173 break;
174 case kInt32:
175 encoder.WriteInt32(provider.ConsumeIntegral<uint32_t>(),
176 provider.ConsumeIntegral<int32_t>());
177 break;
178 case kPackedInt32:
179 encoder.WritePackedInt32(provider.ConsumeIntegral<uint32_t>(),
180 ConsumeSpan<int32_t>(&provider, &s32s));
181 break;
182 case kInt64:
183 encoder.WriteInt64(provider.ConsumeIntegral<uint32_t>(),
184 provider.ConsumeIntegral<int64_t>());
185 break;
186 case kPackedInt64:
187 encoder.WritePackedInt64(provider.ConsumeIntegral<uint32_t>(),
188 ConsumeSpan<int64_t>(&provider, &s64s));
189 break;
190 case kSint32:
191 encoder.WriteSint32(provider.ConsumeIntegral<uint32_t>(),
192 provider.ConsumeIntegral<int32_t>());
193 break;
194 case kPackedSint32:
195 encoder.WritePackedSint32(provider.ConsumeIntegral<uint32_t>(),
196 ConsumeSpan<int32_t>(&provider, &s32s));
197 break;
198 case kSint64:
199 encoder.WriteSint64(provider.ConsumeIntegral<uint32_t>(),
200 provider.ConsumeIntegral<int64_t>());
201 break;
202 case kPackedSint64:
203 encoder.WritePackedSint64(provider.ConsumeIntegral<uint32_t>(),
204 ConsumeSpan<int64_t>(&provider, &s64s));
205 break;
206 case kBool:
207 encoder.WriteBool(provider.ConsumeIntegral<uint32_t>(),
208 provider.ConsumeBool());
209 break;
210 case kFixed32:
211 encoder.WriteFixed32(provider.ConsumeIntegral<uint32_t>(),
212 provider.ConsumeIntegral<uint32_t>());
213 break;
214 case kPackedFixed32:
215 encoder.WritePackedFixed32(provider.ConsumeIntegral<uint32_t>(),
216 ConsumeSpan<uint32_t>(&provider, &u32s));
217 break;
218 case kFixed64:
219 encoder.WriteFixed64(provider.ConsumeIntegral<uint32_t>(),
220 provider.ConsumeIntegral<uint64_t>());
221 break;
222 case kPackedFixed64:
223 encoder.WritePackedFixed64(provider.ConsumeIntegral<uint32_t>(),
224 ConsumeSpan<uint64_t>(&provider, &u64s));
225 break;
226 case kSfixed32:
227 encoder.WriteSfixed32(provider.ConsumeIntegral<uint32_t>(),
228 provider.ConsumeIntegral<int32_t>());
229 break;
230 case kPackedSfixed32:
231 encoder.WritePackedSfixed32(provider.ConsumeIntegral<uint32_t>(),
232 ConsumeSpan<int32_t>(&provider, &s32s));
233 break;
234 case kSfixed64:
235 encoder.WriteSfixed64(provider.ConsumeIntegral<uint32_t>(),
236 provider.ConsumeIntegral<int64_t>());
237 break;
238 case kPackedSfixed64:
239 encoder.WritePackedSfixed64(provider.ConsumeIntegral<uint32_t>(),
240 ConsumeSpan<int64_t>(&provider, &s64s));
241 break;
242 case kFloat:
243 encoder.WriteFloat(provider.ConsumeIntegral<uint32_t>(),
244 provider.ConsumeFloatingPoint<float>());
245 break;
246 case kPackedFloat:
247 encoder.WritePackedFloat(provider.ConsumeIntegral<uint32_t>(),
248 ConsumeSpan<float>(&provider, &floats));
249 break;
250 case kDouble:
251 encoder.WriteDouble(provider.ConsumeIntegral<uint32_t>(),
252 provider.ConsumeFloatingPoint<double>());
253 break;
254 case kPackedDouble:
255 encoder.WritePackedDouble(provider.ConsumeIntegral<uint32_t>(),
256 ConsumeSpan<double>(&provider, &doubles));
257 break;
258 case kBytes:
259 encoder.WriteBytes(provider.ConsumeIntegral<uint32_t>(),
260 ConsumeBytes(&provider, &bytes));
261 break;
262 case kString:
263 encoder.WriteString(provider.ConsumeIntegral<uint32_t>(),
264 ConsumeString(&provider, &strings));
265 break;
266 case kPush:
267 // Special "field". The marks the start of a nested message.
268 encoder.Push(provider.ConsumeIntegral<uint32_t>());
269 break;
270 case kPop:
271 // Special "field". this marks the end of a nested message. No attempt
272 // is made to match pushes to pops, in order to test that the encoder
273 // behaves correctly when they are mismatched.
274 encoder.Pop();
275 break;
276 }
277 }
278 // Ensure we call `Encode` at least once.
Wyatt Hepler86ec8822021-05-21 15:15:24 -0700279 encoder.Encode().IgnoreError();
Aaron Green0ce7f412020-04-06 13:39:40 -0700280
281 // Don't forget to unpoison for the next iteration!
282 ASAN_UNPOISON_MEMORY_REGION(poisoned, poisoned_length);
283 return 0;
284}