1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <cmath>
6 #include <cstddef>
7 #include <cstdint>
8 #include <map>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include <base/logging.h>
14 #include <base/strings/string_util.h>
15 #include <brillo/dbus/data_serialization.h>
16 #include <dbus/string_util.h>
17 #include <fuzzer/FuzzedDataProvider.h>
18
19 namespace {
20 constexpr int kRandomMaxContainerSize = 8;
21 constexpr int kRandomMaxDataLength = 128;
22
23 typedef enum DataType {
24 kUint8 = 0,
25 kUint16,
26 kUint32,
27 kUint64,
28 kInt16,
29 kInt32,
30 kInt64,
31 kBool,
32 kDouble,
33 kString,
34 kObjectPath,
35 // A couple vector types.
36 kVectorInt16,
37 kVectorString,
38 // A couple pair types.
39 kPairBoolInt64,
40 kPairUint32String,
41 // A couple tuple types.
42 kTupleUint16StringBool,
43 kTupleDoubleInt32ObjectPath,
44 // A couple map types.
45 kMapInt32String,
46 kMapDoubleBool,
47 kMaxValue = kMapDoubleBool,
48 } DataType;
49
50 template <typename T>
AppendValue(dbus::MessageWriter * writer,bool variant,const T & value)51 void AppendValue(dbus::MessageWriter* writer, bool variant, const T& value) {
52 if (variant)
53 brillo::dbus_utils::AppendValueToWriterAsVariant(writer, value);
54 else
55 brillo::dbus_utils::AppendValueToWriter(writer, value);
56 }
57
58 template <typename T>
GenerateIntAndAppendValue(FuzzedDataProvider * data_provider,dbus::MessageWriter * writer,bool variant)59 void GenerateIntAndAppendValue(FuzzedDataProvider* data_provider,
60 dbus::MessageWriter* writer,
61 bool variant) {
62 AppendValue(writer, variant, data_provider->ConsumeIntegral<T>());
63 }
64
65 template <typename T>
PopValue(dbus::MessageReader * reader,bool variant,T * value)66 void PopValue(dbus::MessageReader* reader, bool variant, T* value) {
67 if (variant)
68 brillo::dbus_utils::PopVariantValueFromReader(reader, value);
69 else
70 brillo::dbus_utils::PopValueFromReader(reader, value);
71 }
72
GenerateValidUTF8(FuzzedDataProvider * data_provider)73 std::string GenerateValidUTF8(FuzzedDataProvider* data_provider) {
74 // >= 0x80
75 // Generates a random string and returns it if it is valid UTF8, if it is not
76 // then it will strip it down to all the 7-bit ASCII chars and just return
77 // that string.
78 std::string str =
79 data_provider->ConsumeRandomLengthString(kRandomMaxDataLength);
80 if (base::IsStringUTF8(str))
81 return str;
82 for (auto it = str.begin(); it != str.end(); it++) {
83 if (static_cast<uint8_t>(*it) >= 0x80) {
84 // Might be invalid, remove it.
85 it = str.erase(it);
86 it--;
87 }
88 }
89 return str;
90 }
91
92 } // namespace
93
94 class Environment {
95 public:
Environment()96 Environment() {
97 // Disable logging.
98 logging::SetMinLogLevel(logging::LOG_FATAL);
99 }
100 };
101
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)102 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
103 static Environment env;
104 FuzzedDataProvider data_provider(data, size);
105 // Consume a random fraction of our data writing random things to a D-Bus
106 // message, and then consume the remaining data reading randomly from that
107 // same D-Bus message. Given the templated nature of these functions and that
108 // they support essentially an infinite amount of types, we are constraining
109 // this to a fixed set of types defined above.
110 std::unique_ptr<dbus::Response> message = dbus::Response::CreateEmpty();
111 dbus::MessageWriter writer(message.get());
112
113 int bytes_left_for_read =
114 static_cast<int>(data_provider.ConsumeProbability<float>() * size);
115 while (data_provider.remaining_bytes() > bytes_left_for_read) {
116 DataType curr_type = data_provider.ConsumeEnum<DataType>();
117 bool variant = data_provider.ConsumeBool();
118 switch (curr_type) {
119 case kUint8:
120 GenerateIntAndAppendValue<uint8_t>(&data_provider, &writer, variant);
121 break;
122 case kUint16:
123 GenerateIntAndAppendValue<uint16_t>(&data_provider, &writer, variant);
124 break;
125 case kUint32:
126 GenerateIntAndAppendValue<uint32_t>(&data_provider, &writer, variant);
127 break;
128 case kUint64:
129 GenerateIntAndAppendValue<uint64_t>(&data_provider, &writer, variant);
130 break;
131 case kInt16:
132 GenerateIntAndAppendValue<int16_t>(&data_provider, &writer, variant);
133 break;
134 case kInt32:
135 GenerateIntAndAppendValue<int32_t>(&data_provider, &writer, variant);
136 break;
137 case kInt64:
138 GenerateIntAndAppendValue<int64_t>(&data_provider, &writer, variant);
139 break;
140 case kBool:
141 AppendValue(&writer, variant, data_provider.ConsumeBool());
142 break;
143 case kDouble:
144 AppendValue(&writer, variant,
145 data_provider.ConsumeProbability<double>());
146 break;
147 case kString:
148 AppendValue(&writer, variant, GenerateValidUTF8(&data_provider));
149 break;
150 case kObjectPath: {
151 std::string object_path =
152 data_provider.ConsumeRandomLengthString(kRandomMaxDataLength);
153 // If this isn't valid we'll hit a CHECK failure.
154 if (dbus::IsValidObjectPath(object_path))
155 AppendValue(&writer, variant, dbus::ObjectPath(object_path));
156 break;
157 }
158 case kVectorInt16: {
159 int vec_size = data_provider.ConsumeIntegralInRange<int>(
160 0, kRandomMaxContainerSize);
161 std::vector<int16_t> vec(vec_size);
162 for (int i = 0; i < vec_size; i++)
163 vec[i] = data_provider.ConsumeIntegral<int16_t>();
164 AppendValue(&writer, variant, vec);
165 break;
166 }
167 case kVectorString: {
168 int vec_size = data_provider.ConsumeIntegralInRange<int>(
169 0, kRandomMaxContainerSize);
170 std::vector<std::string> vec(vec_size);
171 for (int i = 0; i < vec_size; i++)
172 vec[i] = GenerateValidUTF8(&data_provider);
173 AppendValue(&writer, variant, vec);
174 break;
175 }
176 case kPairBoolInt64:
177 AppendValue(
178 &writer, variant,
179 std::pair<bool, int64_t>{data_provider.ConsumeBool(),
180 data_provider.ConsumeIntegral<int64_t>()});
181 break;
182 case kPairUint32String:
183 AppendValue(&writer, variant,
184 std::pair<uint32_t, std::string>{
185 data_provider.ConsumeIntegral<uint32_t>(),
186 GenerateValidUTF8(&data_provider)});
187 break;
188 case kTupleUint16StringBool:
189 AppendValue(&writer, variant,
190 std::tuple<uint32_t, std::string, bool>{
191 data_provider.ConsumeIntegral<uint32_t>(),
192 GenerateValidUTF8(&data_provider),
193 data_provider.ConsumeBool()});
194 break;
195 case kTupleDoubleInt32ObjectPath: {
196 std::string object_path =
197 data_provider.ConsumeRandomLengthString(kRandomMaxDataLength);
198 // If this isn't valid we'll hit a CHECK failure.
199 if (dbus::IsValidObjectPath(object_path)) {
200 AppendValue(&writer, variant,
201 std::tuple<double, int32_t, dbus::ObjectPath>{
202 data_provider.ConsumeProbability<double>(),
203 data_provider.ConsumeIntegral<int32_t>(),
204 dbus::ObjectPath(object_path)});
205 }
206 break;
207 }
208 case kMapInt32String: {
209 int map_size = data_provider.ConsumeIntegralInRange<int>(
210 0, kRandomMaxContainerSize);
211 std::map<int32_t, std::string> map;
212 for (int i = 0; i < map_size; i++)
213 map[data_provider.ConsumeIntegral<int32_t>()] =
214 GenerateValidUTF8(&data_provider);
215 AppendValue(&writer, variant, map);
216 break;
217 }
218 case kMapDoubleBool: {
219 int map_size = data_provider.ConsumeIntegralInRange<int>(
220 0, kRandomMaxContainerSize);
221 std::map<double, bool> map;
222 for (int i = 0; i < map_size; i++)
223 map[data_provider.ConsumeProbability<double>()] =
224 data_provider.ConsumeBool();
225 AppendValue(&writer, variant, map);
226 break;
227 }
228 }
229 }
230
231 dbus::MessageReader reader(message.get());
232 while (data_provider.remaining_bytes()) {
233 DataType curr_type = data_provider.ConsumeEnum<DataType>();
234 bool variant = data_provider.ConsumeBool();
235 switch (curr_type) {
236 case kUint8: {
237 uint8_t value;
238 PopValue(&reader, variant, &value);
239 break;
240 }
241 case kUint16: {
242 uint16_t value;
243 PopValue(&reader, variant, &value);
244 break;
245 }
246 case kUint32: {
247 uint32_t value;
248 PopValue(&reader, variant, &value);
249 break;
250 }
251 case kUint64: {
252 uint64_t value;
253 PopValue(&reader, variant, &value);
254 break;
255 }
256 case kInt16: {
257 int16_t value;
258 PopValue(&reader, variant, &value);
259 break;
260 }
261 case kInt32: {
262 int32_t value;
263 PopValue(&reader, variant, &value);
264 break;
265 }
266 case kInt64: {
267 int64_t value;
268 PopValue(&reader, variant, &value);
269 break;
270 }
271 case kBool: {
272 bool value;
273 PopValue(&reader, variant, &value);
274 break;
275 }
276 case kDouble: {
277 double value;
278 PopValue(&reader, variant, &value);
279 break;
280 }
281 case kString: {
282 std::string value;
283 PopValue(&reader, variant, &value);
284 break;
285 }
286 case kObjectPath: {
287 dbus::ObjectPath value;
288 PopValue(&reader, variant, &value);
289 break;
290 }
291 case kVectorInt16: {
292 std::vector<int16_t> value;
293 PopValue(&reader, variant, &value);
294 break;
295 }
296 case kVectorString: {
297 std::vector<std::string> value;
298 PopValue(&reader, variant, &value);
299 break;
300 }
301 case kPairBoolInt64: {
302 std::pair<bool, int64_t> value;
303 PopValue(&reader, variant, &value);
304 break;
305 }
306 case kPairUint32String: {
307 std::pair<uint32_t, std::string> value;
308 PopValue(&reader, variant, &value);
309 break;
310 }
311 case kTupleUint16StringBool: {
312 std::tuple<uint16_t, std::string, bool> value;
313 break;
314 }
315 case kTupleDoubleInt32ObjectPath: {
316 std::tuple<double, int32_t, dbus::ObjectPath> value;
317 PopValue(&reader, variant, &value);
318 break;
319 }
320 case kMapInt32String: {
321 std::map<int32_t, std::string> value;
322 PopValue(&reader, variant, &value);
323 break;
324 }
325 case kMapDoubleBool: {
326 std::map<double, bool> value;
327 PopValue(&reader, variant, &value);
328 break;
329 }
330 }
331 }
332
333 return 0;
334 }
335