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