• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium 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 <stddef.h>
6 #include <stdint.h>
7 
8 #include "base/containers/flat_map.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/task_scheduler/task_scheduler.h"
13 #include "mojo/core/embedder/embedder.h"
14 #include "mojo/public/tools/fuzzers/fuzz.mojom.h"
15 #include "mojo/public/tools/fuzzers/fuzz_impl.h"
16 
17 /* Environment for the executable. Initializes the mojo EDK and sets up a
18  * TaskScheduler, because Mojo messages must be sent and processed from
19  * TaskRunners. */
20 struct Environment {
EnvironmentEnvironment21   Environment() : message_loop() {
22     base::TaskScheduler::CreateAndStartWithDefaultParams(
23         "MojoFuzzerMessageDumpProcess");
24     mojo::core::Init();
25   }
26 
27   /* Message loop to send messages on. */
28   base::MessageLoop message_loop;
29 
30   /* Impl to be created. Stored in environment to keep it alive after
31    * DumpMessages returns. */
32   std::unique_ptr<FuzzImpl> impl;
33 };
34 
35 Environment* env = new Environment();
36 
37 /* MessageReceiver which dumps raw message bytes to disk in the provided
38  * directory. */
39 class MessageDumper : public mojo::MessageReceiver {
40  public:
MessageDumper(std::string directory)41   explicit MessageDumper(std::string directory)
42       : directory_(directory), count_(0) {}
43 
Accept(mojo::Message * message)44   bool Accept(mojo::Message* message) override {
45     base::FilePath path = directory_.Append(FILE_PATH_LITERAL("message_") +
46                                             base::IntToString(count_++) +
47                                             FILE_PATH_LITERAL(".mojomsg"));
48 
49     base::File file(path,
50                     base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
51     if (!file.IsValid()) {
52       LOG(ERROR) << "Failed to create mojo message file: " << path.value();
53       return false;
54     }
55 
56     size_t size = message->data_num_bytes();
57     const char* data = reinterpret_cast<const char*>(message->data());
58     int ret = file.WriteAtCurrentPos(data, size);
59     if (ret != static_cast<int>(size)) {
60       LOG(ERROR) << "Failed to write " << size << " bytes.";
61       return false;
62     }
63     return true;
64   }
65 
66   base::FilePath directory_;
67   int count_;
68 };
69 
70 /* Returns a FuzzUnion with fuzz_bool initialized. */
GetBoolFuzzUnion()71 auto GetBoolFuzzUnion() {
72   fuzz::mojom::FuzzUnionPtr union_bool = fuzz::mojom::FuzzUnion::New();
73   union_bool->set_fuzz_bool(true);
74   return union_bool;
75 }
76 
77 /* Returns a FuzzUnion with fuzz_struct_map initialized. Takes in a
78  * FuzzDummyStructPtr to use within the fuzz_struct_map value. */
GetStructMapFuzzUnion(fuzz::mojom::FuzzDummyStructPtr in)79 auto GetStructMapFuzzUnion(fuzz::mojom::FuzzDummyStructPtr in) {
80   fuzz::mojom::FuzzUnionPtr union_struct_map = fuzz::mojom::FuzzUnion::New();
81   base::flat_map<std::string, fuzz::mojom::FuzzDummyStructPtr> struct_map;
82   struct_map["fuzz"] = std::move(in);
83   union_struct_map->set_fuzz_struct_map(std::move(struct_map));
84   return union_struct_map;
85 }
86 
87 /* Returns a FuzzUnion with fuzz_complex initialized. Takes in a FuzzUnionPtr
88  * to use within the fuzz_complex value. */
GetComplexFuzzUnion(fuzz::mojom::FuzzUnionPtr in)89 auto GetComplexFuzzUnion(fuzz::mojom::FuzzUnionPtr in) {
90   std::remove_reference<decltype(in->get_fuzz_complex())>::type complex_map;
91   std::remove_reference<decltype(complex_map.value()[0])>::type outer;
92   std::remove_reference<decltype(
93       outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0])>::type inner;
94   std::remove_reference<decltype(inner['z'])>::type center;
95 
96   center.emplace();
97   center.value().push_back(std::move(in));
98   inner['z'] = std::move(center);
99   outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0] = std::move(inner);
100   complex_map.emplace();
101   complex_map.value().push_back(std::move(outer));
102 
103   fuzz::mojom::FuzzUnionPtr union_complex = fuzz::mojom::FuzzUnion::New();
104   union_complex->set_fuzz_complex(std::move(complex_map));
105   return union_complex;
106 }
107 
108 /* Returns a populated value for FuzzStruct->fuzz_primitive_array. */
GetFuzzStructPrimitiveArrayValue()109 auto GetFuzzStructPrimitiveArrayValue() {
110   decltype(fuzz::mojom::FuzzStruct::fuzz_primitive_array) primitive_array;
111   primitive_array = {'f', 'u', 'z', 'z'};
112   return primitive_array;
113 }
114 
115 /* Returns a populated value for FuzzStruct->fuzz_primitive_map. */
GetFuzzStructPrimitiveMapValue()116 auto GetFuzzStructPrimitiveMapValue() {
117   decltype(fuzz::mojom::FuzzStruct::fuzz_primitive_map) primitive_map;
118   primitive_map["fuzz"] = 'z';
119   return primitive_map;
120 }
121 
122 /* Returns a populated value for FuzzStruct->fuzz_array_map. */
GetFuzzStructArrayMapValue()123 auto GetFuzzStructArrayMapValue() {
124   decltype(fuzz::mojom::FuzzStruct::fuzz_array_map) array_map;
125   array_map["fuzz"] = {"fuzz1", "fuzz2"};
126   return array_map;
127 }
128 
129 /* Returns a populated value for FuzzStruct->fuzz_union_map. Takes in a
130  * FuzzUnionPtr to use within the fuzz_union_map value.*/
GetFuzzStructUnionMapValue(fuzz::mojom::FuzzUnionPtr in)131 auto GetFuzzStructUnionMapValue(fuzz::mojom::FuzzUnionPtr in) {
132   decltype(fuzz::mojom::FuzzStruct::fuzz_union_map) union_map;
133   union_map[fuzz::mojom::FuzzEnum::FUZZ_VALUE1] = std::move(in);
134   return union_map;
135 }
136 
137 /* Returns a populated value for FuzzStruct->fuzz_union_array. Takes in a
138  * FuzzUnionPtr to use within the fuzz_union_array value.*/
GetFuzzStructUnionArrayValue(fuzz::mojom::FuzzUnionPtr in)139 auto GetFuzzStructUnionArrayValue(fuzz::mojom::FuzzUnionPtr in) {
140   decltype(fuzz::mojom::FuzzStruct::fuzz_union_array) union_array;
141   union_array.push_back(std::move(in));
142   return union_array;
143 }
144 
145 /* Returns a populated value for FuzzStruct->fuzz_struct_array. Takes in a
146  * FuzzStructPtr to use within the fuzz_struct_array value. */
GetFuzzStructStructArrayValue(fuzz::mojom::FuzzStructPtr in)147 auto GetFuzzStructStructArrayValue(fuzz::mojom::FuzzStructPtr in) {
148   decltype(fuzz::mojom::FuzzStruct::fuzz_struct_array) struct_array;
149   struct_array.push_back(std::move(in));
150   return struct_array;
151 }
152 
153 /* Returns a populated value for FuzzStruct->fuzz_nullable_array. */
GetFuzzStructNullableArrayValue()154 auto GetFuzzStructNullableArrayValue() {
155   decltype(fuzz::mojom::FuzzStruct::fuzz_nullable_array) nullable_array;
156   return nullable_array;
157 }
158 
159 /* Returns a populated value for FuzzStruct->fuzz_complex. */
GetFuzzStructComplexValue()160 auto GetFuzzStructComplexValue() {
161   decltype(fuzz::mojom::FuzzStruct::fuzz_complex) complex_map;
162   std::remove_reference<decltype(complex_map.value()[0])>::type outer;
163   std::remove_reference<decltype(
164       outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0])>::type inner;
165   std::remove_reference<decltype(inner['z'])>::type center;
166 
167   center.emplace();
168   center.value().push_back(fuzz::mojom::FuzzStruct::New());
169   inner['z'] = std::move(center);
170   outer[fuzz::mojom::FuzzEnum::FUZZ_VALUE0] = std::move(inner);
171   complex_map.emplace();
172   complex_map.value().push_back(std::move(outer));
173   return complex_map;
174 }
175 
176 /* Returns a FuzzStruct with its fields populated. */
GetPopulatedFuzzStruct()177 fuzz::mojom::FuzzStructPtr GetPopulatedFuzzStruct() {
178   /* Make some populated Unions. */
179   auto union_bool = GetBoolFuzzUnion();
180   auto union_struct_map =
181       GetStructMapFuzzUnion(fuzz::mojom::FuzzDummyStruct::New());
182   auto union_complex = GetComplexFuzzUnion(std::move(union_bool));
183 
184   /* Prepare the nontrivial fields for the struct. */
185   auto fuzz_primitive_array = GetFuzzStructPrimitiveArrayValue();
186   auto fuzz_primitive_map = GetFuzzStructPrimitiveMapValue();
187   auto fuzz_array_map = GetFuzzStructArrayMapValue();
188   auto fuzz_union_map = GetFuzzStructUnionMapValue(std::move(union_struct_map));
189   auto fuzz_union_array =
190       GetFuzzStructUnionArrayValue(std::move(union_complex));
191   auto fuzz_struct_array =
192       GetFuzzStructStructArrayValue(fuzz::mojom::FuzzStruct::New());
193   auto fuzz_nullable_array = GetFuzzStructNullableArrayValue();
194   auto fuzz_complex = GetFuzzStructComplexValue();
195 
196   /* Make a populated struct and return it. */
197   return fuzz::mojom::FuzzStruct::New(
198       true,                            /* fuzz_bool */
199       -1,                              /* fuzz_int8 */
200       1,                               /* fuzz_uint8 */
201       -(1 << 8),                       /* fuzz_int16 */
202       1 << 8,                          /* fuzz_uint16 */
203       -(1 << 16),                      /* fuzz_int32 */
204       1 << 16,                         /* fuzz_uint32 */
205       -((int64_t)1 << 32),             /* fuzz_int64 */
206       (uint64_t)1 << 32,               /* fuzz_uint64 */
207       1.0,                             /* fuzz_float */
208       1.0,                             /* fuzz_double */
209       "fuzz",                          /* fuzz_string */
210       std::move(fuzz_primitive_array), /* fuzz_primitive_array */
211       std::move(fuzz_primitive_map),   /* fuzz_primitive_map */
212       std::move(fuzz_array_map),       /* fuzz_array_map */
213       std::move(fuzz_union_map),       /* fuzz_union_map */
214       std::move(fuzz_union_array),     /* fuzz_union_array */
215       std::move(fuzz_struct_array),    /* fuzz_struct_array */
216       std::move(fuzz_nullable_array),  /* fuzz_nullable_array */
217       std::move(fuzz_complex));        /* fuzz_complex */
218 }
219 
220 /* Callback used for messages with responses. Does nothing. */
FuzzCallback()221 void FuzzCallback() {}
222 
223 /* Invokes each method in the FuzzInterface and dumps the messages to the
224  * supplied directory. */
DumpMessages(std::string output_directory)225 void DumpMessages(std::string output_directory) {
226   fuzz::mojom::FuzzInterfacePtr fuzz;
227   fuzz::mojom::FuzzDummyInterfaceAssociatedPtr dummy;
228 
229   /* Create the impl and add a MessageDumper to the filter chain. */
230   env->impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz));
231   env->impl->binding_.RouterForTesting()->AddIncomingMessageFilter(
232       std::make_unique<MessageDumper>(output_directory));
233 
234   /* Call methods in various ways to generate interesting messages. */
235   fuzz->FuzzBasic();
236   fuzz->FuzzBasicResp(base::Bind(FuzzCallback));
237   fuzz->FuzzBasicSyncResp();
238   fuzz->FuzzArgs(fuzz::mojom::FuzzStruct::New(),
239                  fuzz::mojom::FuzzStructPtr(nullptr));
240   fuzz->FuzzArgs(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct());
241   fuzz->FuzzArgsResp(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct(),
242                      base::Bind(FuzzCallback));
243   fuzz->FuzzArgsResp(fuzz::mojom::FuzzStruct::New(), GetPopulatedFuzzStruct(),
244                      base::Bind(FuzzCallback));
245   fuzz->FuzzArgsSyncResp(fuzz::mojom::FuzzStruct::New(),
246                          GetPopulatedFuzzStruct(), base::Bind(FuzzCallback));
247   fuzz->FuzzArgsSyncResp(fuzz::mojom::FuzzStruct::New(),
248                          GetPopulatedFuzzStruct(), base::Bind(FuzzCallback));
249   fuzz->FuzzAssociated(MakeRequest(&dummy));
250   dummy->Ping();
251 }
252 
main(int argc,char ** argv)253 int main(int argc, char** argv) {
254   if (argc < 2) {
255     printf("Usage: %s [output_directory]\n", argv[0]);
256     exit(1);
257   }
258   std::string output_directory(argv[1]);
259 
260   /* Dump the messages from a MessageLoop, and wait for it to finish. */
261   env->message_loop.task_runner()->PostTask(
262       FROM_HERE, base::BindOnce(&DumpMessages, output_directory));
263   base::RunLoop().RunUntilIdle();
264 
265   return 0;
266 }
267