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.
9 #include "base/command_line.h"
10 #include "base/strings/string_split.h"
11 #include "ipc/ipc_message_macros.h"
12 #include "tools/ipc_fuzzer/fuzzer/fuzzer.h"
13 #include "tools/ipc_fuzzer/fuzzer/generator.h"
14 #include "tools/ipc_fuzzer/fuzzer/mutator.h"
15 #include "tools/ipc_fuzzer/fuzzer/rand_util.h"
16 #include "tools/ipc_fuzzer/message_lib/message_file.h"
18 namespace ipc_fuzzer
{
22 // TODO(mbarbella): Check to see if this value is actually reasonable.
23 const int kFrequency
= 23;
25 const char kCountSwitch
[] = "count";
26 const char kCountSwitchHelp
[] =
27 "Number of messages to generate (generator).";
29 const char kFrequencySwitch
[] = "frequency";
30 const char kFrequencySwitchHelp
[] =
31 "Probability of mutation; tweak every 1/|q| times (mutator).";
33 const char kFuzzerNameSwitch
[] = "fuzzer-name";
34 const char kFuzzerNameSwitchHelp
[] =
35 "Select generator, mutator, or no-op fuzzer. Default: generator";
37 const char kHelpSwitch
[] = "help";
38 const char kHelpSwitchHelp
[] =
41 const char kPermuteSwitch
[] = "permute";
42 const char kPermuteSwitchHelp
[] =
43 "Randomly shuffle the order of all messages (mutator).";
45 const char kTypeListSwitch
[] = "type-list";
46 const char kTypeListSwitchHelp
[] =
47 "Explicit list of the only message-ids to mutate (mutator).";
50 std::cerr
<< "Mutate messages from an exiting message file.\n";
52 std::cerr
<< "Usage:\n"
54 << " [--" << kCountSwitch
<< "=c]"
55 << " [--" << kFrequencySwitch
<< "=q]"
56 << " [--" << kFuzzerNameSwitch
<< "=f]"
57 << " [--" << kHelpSwitch
<< "]"
58 << " [--" << kTypeListSwitch
<< "=x,y,z...]"
59 << " [--" << kPermuteSwitch
<< "]"
60 << " [infile (mutation only)] outfile\n";
63 << " --" << kCountSwitch
<< " - " << kCountSwitchHelp
<< "\n"
64 << " --" << kFrequencySwitch
<< " - " << kFrequencySwitchHelp
<< "\n"
65 << " --" << kFuzzerNameSwitch
<< " - " << kFuzzerNameSwitchHelp
<< "\n"
66 << " --" << kHelpSwitch
<< " - " << kHelpSwitchHelp
<< "\n"
67 << " --" << kTypeListSwitch
<< " - " << kTypeListSwitchHelp
<< "\n"
68 << " --" << kPermuteSwitch
<< " - " << kPermuteSwitchHelp
<< "\n";
75 static Fuzzer
*Create(const std::string
& name
, int frequency
) {
76 if (name
== "default")
77 return new Generator();
79 if (name
== "generate")
80 return new Generator();
83 return new Mutator(frequency
);
86 return new NoOpFuzzer();
88 std::cerr
<< "No such fuzzer: " << name
<< "\n";
93 static IPC::Message
* RewriteMessage(
94 IPC::Message
* message
,
96 FuzzerFunctionMap
* map
) {
97 FuzzerFunctionMap::iterator it
= map
->find(message
->type());
98 if (it
== map
->end()) {
99 // This usually indicates a missing message file in all_messages.h, or
100 // that the message dump file is taken from a different revision of
101 // chromium from this executable.
102 std::cerr
<< "Unknown message type: ["
103 << IPC_MESSAGE_ID_CLASS(message
->type()) << ", "
104 << IPC_MESSAGE_ID_LINE(message
->type()) << "].\n";
108 return (*it
->second
)(message
, fuzzer
);
111 int Generate(base::CommandLine
* cmd
, Fuzzer
* fuzzer
) {
112 base::CommandLine::StringVector args
= cmd
->GetArgs();
113 if (args
.size() != 1) {
117 base::FilePath::StringType output_file_name
= args
[0];
119 int message_count
= 1000;
120 if (cmd
->HasSwitch(kCountSwitch
))
121 message_count
= atoi(cmd
->GetSwitchValueASCII(kCountSwitch
).c_str());
123 MessageVector message_vector
;
125 if (message_count
< 0) {
126 // Enumerate them all.
127 for (size_t i
= 0; i
< g_function_vector
.size(); ++i
) {
128 if (IPC::Message
* new_message
= (*g_function_vector
[i
])(NULL
, fuzzer
))
129 message_vector
.push_back(new_message
);
134 // Fuzz a random batch.
135 for (int i
= 0; i
< message_count
; ++i
) {
136 size_t index
= RandInRange(g_function_vector
.size());
137 if (IPC::Message
* new_message
= (*g_function_vector
[index
])(NULL
, fuzzer
))
138 message_vector
.push_back(new_message
);
144 std::cerr
<< "Failed to generate " << bad_count
<< " messages.\n";
145 if (!MessageFile::Write(base::FilePath(output_file_name
), message_vector
))
150 int Mutate(base::CommandLine
* cmd
, Fuzzer
* fuzzer
) {
151 base::CommandLine::StringVector args
= cmd
->GetArgs();
152 if (args
.size() != 2) {
156 base::FilePath::StringType input_file_name
= args
[0];
157 base::FilePath::StringType output_file_name
= args
[1];
159 bool permute
= cmd
->HasSwitch(kPermuteSwitch
);
161 std::string type_string_list
= cmd
->GetSwitchValueASCII(kTypeListSwitch
);
162 std::vector
<std::string
> type_string_vector
= base::SplitString(
163 type_string_list
, ",", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
164 std::set
<uint32
> type_set
;
165 for (size_t i
= 0; i
< type_string_vector
.size(); ++i
) {
166 type_set
.insert(atoi(type_string_vector
[i
].c_str()));
169 FuzzerFunctionMap fuzz_function_map
;
170 PopulateFuzzerFunctionMap(&fuzz_function_map
);
172 MessageVector message_vector
;
173 if (!MessageFile::Read(base::FilePath(input_file_name
), &message_vector
))
176 for (size_t i
= 0; i
< message_vector
.size(); ++i
) {
177 IPC::Message
* msg
= message_vector
[i
];
178 // If an explicit type set is specified, make sure we should be mutating
179 // this message type on this run.
180 if (!type_set
.empty() && type_set
.end() == std::find(
181 type_set
.begin(), type_set
.end(), msg
->type())) {
184 IPC::Message
* new_message
= RewriteMessage(msg
, fuzzer
, &fuzz_function_map
);
186 IPC::Message
* old_message
= message_vector
[i
];
188 message_vector
[i
] = new_message
;
193 std::random_shuffle(message_vector
.begin(), message_vector
.end(),
197 if (!MessageFile::Write(base::FilePath(output_file_name
), message_vector
))
202 int FuzzerMain(int argc
, char** argv
) {
203 base::CommandLine::Init(argc
, argv
);
204 base::CommandLine
* cmd
= base::CommandLine::ForCurrentProcess();
205 base::CommandLine::StringVector args
= cmd
->GetArgs();
207 if (args
.size() == 0 || args
.size() > 2 || cmd
->HasSwitch(kHelpSwitch
)) {
214 PopulateFuzzerFunctionVector(&g_function_vector
);
215 std::cerr
<< "Counted " << g_function_vector
.size()
216 << " distinct messages present in chrome.\n";
218 std::string fuzzer_name
= "default";
219 if (cmd
->HasSwitch(kFuzzerNameSwitch
))
220 fuzzer_name
= cmd
->GetSwitchValueASCII(kFuzzerNameSwitch
);
222 int frequency
= kFrequency
;
223 if (cmd
->HasSwitch(kFrequencySwitch
))
224 frequency
= atoi(cmd
->GetSwitchValueASCII(kFrequencySwitch
).c_str());
226 Fuzzer
* fuzzer
= FuzzerFactory::Create(fuzzer_name
, frequency
);
231 base::FilePath::StringType output_file_name
;
232 if (fuzzer_name
== "default" || fuzzer_name
== "generate") {
233 result
= Generate(cmd
, fuzzer
);
235 result
= Mutate(cmd
, fuzzer
);
241 } // namespace ipc_fuzzer
243 int main(int argc
, char** argv
) {
244 return ipc_fuzzer::FuzzerMain(argc
, argv
);