xref: /aosp_15_r20/external/libbrillo/brillo/dbus/data_serialization_fuzzer.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
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