1 // Copyright 2015 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 <iostream>
9 #include <set>
10 #include <utility>
11 #include <vector>
12
13 #include "base/command_line.h"
14 #include "base/strings/string_split.h"
15 #include "ipc/ipc_message_macros.h"
16 #include "tools/ipc_fuzzer/fuzzer/fuzzer.h"
17 #include "tools/ipc_fuzzer/fuzzer/generator.h"
18 #include "tools/ipc_fuzzer/fuzzer/mutator.h"
19 #include "tools/ipc_fuzzer/fuzzer/rand_util.h"
20 #include "tools/ipc_fuzzer/message_lib/message_file.h"
21
22 namespace ipc_fuzzer {
23
24 namespace {
25
26 // TODO(mbarbella): Check to see if this value is actually reasonable.
27 const int kFrequency = 23;
28
29 const char kCountSwitch[] = "count";
30 const char kCountSwitchHelp[] =
31 "Number of messages to generate (generator).";
32
33 const char kFrequencySwitch[] = "frequency";
34 const char kFrequencySwitchHelp[] =
35 "Probability of mutation; tweak every 1/|q| times (mutator).";
36
37 const char kFuzzerNameSwitch[] = "fuzzer-name";
38 const char kFuzzerNameSwitchHelp[] =
39 "Select from generate, mutate, or no-op. Default: generate";
40
41 const char kHelpSwitch[] = "help";
42 const char kHelpSwitchHelp[] =
43 "Show this message.";
44
45 const char kPermuteSwitch[] = "permute";
46 const char kPermuteSwitchHelp[] =
47 "Randomly shuffle the order of all messages (mutator).";
48
49 const char kTypeListSwitch[] = "type-list";
50 const char kTypeListSwitchHelp[] =
51 "Explicit list of the only message-ids to mutate (mutator).";
52
usage()53 void usage() {
54 std::cerr << "Mutate messages from an exiting message file.\n";
55
56 std::cerr << "Usage:\n"
57 << " ipc_fuzzer"
58 << " [--" << kCountSwitch << "=c]"
59 << " [--" << kFrequencySwitch << "=q]"
60 << " [--" << kFuzzerNameSwitch << "=f]"
61 << " [--" << kHelpSwitch << "]"
62 << " [--" << kTypeListSwitch << "=x,y,z...]"
63 << " [--" << kPermuteSwitch << "]"
64 << " [infile (mutation only)] outfile\n";
65
66 std::cerr
67 << " --" << kCountSwitch << " - " << kCountSwitchHelp << "\n"
68 << " --" << kFrequencySwitch << " - " << kFrequencySwitchHelp << "\n"
69 << " --" << kFuzzerNameSwitch << " - " << kFuzzerNameSwitchHelp << "\n"
70 << " --" << kHelpSwitch << " - " << kHelpSwitchHelp << "\n"
71 << " --" << kTypeListSwitch << " - " << kTypeListSwitchHelp << "\n"
72 << " --" << kPermuteSwitch << " - " << kPermuteSwitchHelp << "\n";
73 }
74
75 } // namespace
76
77 class FuzzerFactory {
78 public:
Create(const std::string & name,int frequency)79 static Fuzzer *Create(const std::string& name, int frequency) {
80 if (name == "default")
81 return new Generator();
82
83 if (name == "generate")
84 return new Generator();
85
86 if (name == "mutate")
87 return new Mutator(frequency);
88
89 if (name == "no-op")
90 return new NoOpFuzzer();
91
92 std::cerr << "No such fuzzer: " << name << "\n";
93 return 0;
94 }
95 };
96
RewriteMessage(IPC::Message * message,Fuzzer * fuzzer,FuzzerFunctionMap * map)97 static std::unique_ptr<IPC::Message> RewriteMessage(IPC::Message* message,
98 Fuzzer* fuzzer,
99 FuzzerFunctionMap* map) {
100 FuzzerFunctionMap::iterator it = map->find(message->type());
101 if (it == map->end()) {
102 // This usually indicates a missing message file in all_messages.h, or
103 // that the message dump file is taken from a different revision of
104 // chromium from this executable.
105 std::cerr << "Unknown message type: ["
106 << IPC_MESSAGE_ID_CLASS(message->type()) << ", "
107 << IPC_MESSAGE_ID_LINE(message->type()) << "].\n";
108 return 0;
109 }
110
111 return (*it->second)(message, fuzzer);
112 }
113
Generate(base::CommandLine * cmd,Fuzzer * fuzzer)114 int Generate(base::CommandLine* cmd, Fuzzer* fuzzer) {
115 base::CommandLine::StringVector args = cmd->GetArgs();
116 if (args.size() != 1) {
117 usage();
118 return EXIT_FAILURE;
119 }
120 base::FilePath::StringType output_file_name = args[0];
121
122 int message_count = 1000;
123 if (cmd->HasSwitch(kCountSwitch))
124 message_count = atoi(cmd->GetSwitchValueASCII(kCountSwitch).c_str());
125
126 MessageVector message_vector;
127 int bad_count = 0;
128 if (message_count < 0) {
129 // Enumerate them all.
130 for (size_t i = 0; i < g_function_vector.size(); ++i) {
131 std::unique_ptr<IPC::Message> new_message =
132 (*g_function_vector[i])(nullptr, fuzzer);
133 if (new_message)
134 message_vector.push_back(std::move(new_message));
135 else
136 bad_count += 1;
137 }
138 } else {
139 // Fuzz a random batch.
140 for (int i = 0; i < message_count; ++i) {
141 size_t index = RandInRange(g_function_vector.size());
142 std::unique_ptr<IPC::Message> new_message =
143 (*g_function_vector[index])(nullptr, fuzzer);
144 if (new_message)
145 message_vector.push_back(std::move(new_message));
146 else
147 bad_count += 1;
148 }
149 }
150
151 std::cerr << "Failed to generate " << bad_count << " messages.\n";
152 if (!MessageFile::Write(base::FilePath(output_file_name), message_vector))
153 return EXIT_FAILURE;
154 return EXIT_SUCCESS;
155 }
156
Mutate(base::CommandLine * cmd,Fuzzer * fuzzer)157 int Mutate(base::CommandLine* cmd, Fuzzer* fuzzer) {
158 base::CommandLine::StringVector args = cmd->GetArgs();
159 if (args.size() != 2) {
160 usage();
161 return EXIT_FAILURE;
162 }
163 base::FilePath::StringType input_file_name = args[0];
164 base::FilePath::StringType output_file_name = args[1];
165
166 bool permute = cmd->HasSwitch(kPermuteSwitch);
167
168 std::string type_string_list = cmd->GetSwitchValueASCII(kTypeListSwitch);
169 std::vector<std::string> type_string_vector = base::SplitString(
170 type_string_list, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
171 std::set<uint32_t> type_set;
172 for (size_t i = 0; i < type_string_vector.size(); ++i) {
173 type_set.insert(atoi(type_string_vector[i].c_str()));
174 }
175
176 FuzzerFunctionMap fuzz_function_map;
177 PopulateFuzzerFunctionMap(&fuzz_function_map);
178
179 MessageVector message_vector;
180 if (!MessageFile::Read(base::FilePath(input_file_name), &message_vector))
181 return EXIT_FAILURE;
182
183 for (size_t i = 0; i < message_vector.size(); ++i) {
184 IPC::Message* msg = message_vector[i].get();
185 // If an explicit type set is specified, make sure we should be mutating
186 // this message type on this run.
187 if (!type_set.empty() && type_set.end() == std::find(
188 type_set.begin(), type_set.end(), msg->type())) {
189 continue;
190 }
191 std::unique_ptr<IPC::Message> new_message =
192 RewriteMessage(msg, fuzzer, &fuzz_function_map);
193 if (new_message)
194 message_vector[i] = std::move(new_message);
195 }
196
197 if (permute) {
198 std::shuffle(message_vector.begin(), message_vector.end(),
199 *g_mersenne_twister);
200 }
201
202 if (!MessageFile::Write(base::FilePath(output_file_name), message_vector))
203 return EXIT_FAILURE;
204 return EXIT_SUCCESS;
205 }
206
FuzzerMain(int argc,char ** argv)207 int FuzzerMain(int argc, char** argv) {
208 base::CommandLine::Init(argc, argv);
209 base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
210 base::CommandLine::StringVector args = cmd->GetArgs();
211
212 if (args.size() == 0 || args.size() > 2 || cmd->HasSwitch(kHelpSwitch)) {
213 usage();
214 return EXIT_FAILURE;
215 }
216
217 InitRand();
218
219 PopulateFuzzerFunctionVector(&g_function_vector);
220 std::cerr << "Counted " << g_function_vector.size()
221 << " distinct messages present in chrome.\n";
222
223 std::string fuzzer_name = "default";
224 if (cmd->HasSwitch(kFuzzerNameSwitch))
225 fuzzer_name = cmd->GetSwitchValueASCII(kFuzzerNameSwitch);
226
227 int frequency = kFrequency;
228 if (cmd->HasSwitch(kFrequencySwitch))
229 frequency = atoi(cmd->GetSwitchValueASCII(kFrequencySwitch).c_str());
230
231 Fuzzer* fuzzer = FuzzerFactory::Create(fuzzer_name, frequency);
232 if (!fuzzer)
233 return EXIT_FAILURE;
234
235 int result;
236 base::FilePath::StringType output_file_name;
237 if (fuzzer_name == "default" || fuzzer_name == "generate") {
238 result = Generate(cmd, fuzzer);
239 } else {
240 result = Mutate(cmd, fuzzer);
241 }
242
243 return result;
244 }
245
246 } // namespace ipc_fuzzer
247
main(int argc,char ** argv)248 int main(int argc, char** argv) {
249 return ipc_fuzzer::FuzzerMain(argc, argv);
250 }
251