| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdlib.h> |
| |
| #include <algorithm> |
| #include <iostream> |
| #include <ostream> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/pickle.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "ipc/ipc_message.h" |
| #include "ipc/ipc_message_utils.h" |
| #include "ipc/ipc_switches.h" |
| #include "ipc/ipc_sync_channel.h" |
| #include "ipc/ipc_sync_message.h" |
| #include "tools/ipc_fuzzer/message_lib/all_messages.h" |
| #include "tools/ipc_fuzzer/message_lib/message_cracker.h" |
| #include "tools/ipc_fuzzer/message_lib/message_file.h" |
| #include "tools/ipc_fuzzer/mutate/rand_util.h" |
| |
| #if defined(OS_POSIX) |
| #include <unistd.h> |
| #endif |
| |
| namespace IPC { |
| class Message; |
| } // namespace IPC |
| |
| namespace ipc_fuzzer { |
| |
| // Interface implemented by those who fuzz basic types. The types all |
| // correspond to the types which a pickle from base/pickle.h can pickle, |
| // plus the floating point types. |
| class Fuzzer { |
| public: |
| // Tweak individual values within a message. |
| virtual void FuzzBool(bool* value) = 0; |
| virtual void FuzzInt(int* value) = 0; |
| virtual void FuzzLong(long* value) = 0; |
| virtual void FuzzSize(size_t* value) = 0; |
| virtual void FuzzUChar(unsigned char *value) = 0; |
| virtual void FuzzUInt16(uint16* value) = 0; |
| virtual void FuzzUInt32(uint32* value) = 0; |
| virtual void FuzzInt64(int64* value) = 0; |
| virtual void FuzzUInt64(uint64* value) = 0; |
| virtual void FuzzFloat(float *value) = 0; |
| virtual void FuzzDouble(double *value) = 0; |
| virtual void FuzzString(std::string* value) = 0; |
| virtual void FuzzString16(base::string16* value) = 0; |
| virtual void FuzzData(char* data, int length) = 0; |
| virtual void FuzzBytes(void* data, int data_len) = 0; |
| }; |
| |
| template <typename T> |
| void FuzzIntegralType(T* value, unsigned int frequency) { |
| if (RandEvent(frequency)) { |
| switch (RandInRange(4)) { |
| case 0: (*value) = 0; break; |
| case 1: (*value)--; break; |
| case 2: (*value)++; break; |
| case 3: (*value) = RandU64(); break; |
| } |
| } |
| } |
| |
| template <typename T> |
| void FuzzStringType(T* value, unsigned int frequency, |
| const T& literal1, const T& literal2) { |
| if (RandEvent(frequency)) { |
| switch (RandInRange(5)) { |
| case 4: (*value) = (*value) + (*value); // FALLTHROUGH |
| case 3: (*value) = (*value) + (*value); // FALLTHROUGH |
| case 2: (*value) = (*value) + (*value); break; |
| case 1: (*value) += literal1; break; |
| case 0: (*value) = literal2; break; |
| } |
| } |
| } |
| |
| // One such fuzzer implementation. |
| class DefaultFuzzer : public Fuzzer { |
| public: |
| DefaultFuzzer(int frequency) : frequency_(frequency) { |
| } |
| |
| virtual ~DefaultFuzzer() {} |
| |
| virtual void FuzzBool(bool* value) OVERRIDE { |
| if (RandEvent(frequency_)) |
| (*value) = !(*value); |
| } |
| |
| virtual void FuzzInt(int* value) OVERRIDE { |
| FuzzIntegralType<int>(value, frequency_); |
| } |
| |
| virtual void FuzzLong(long* value) OVERRIDE { |
| FuzzIntegralType<long>(value, frequency_); |
| } |
| |
| virtual void FuzzSize(size_t* value) OVERRIDE { |
| FuzzIntegralType<size_t>(value, frequency_); |
| } |
| |
| virtual void FuzzUChar(unsigned char* value) OVERRIDE { |
| FuzzIntegralType<unsigned char>(value, frequency_); |
| } |
| |
| virtual void FuzzUInt16(uint16* value) OVERRIDE { |
| FuzzIntegralType<uint16>(value, frequency_); |
| } |
| |
| virtual void FuzzUInt32(uint32* value) OVERRIDE { |
| FuzzIntegralType<uint32>(value, frequency_); |
| } |
| |
| virtual void FuzzInt64(int64* value) OVERRIDE { |
| FuzzIntegralType<int64>(value, frequency_); |
| } |
| |
| virtual void FuzzUInt64(uint64* value) OVERRIDE { |
| FuzzIntegralType<uint64>(value, frequency_); |
| } |
| |
| virtual void FuzzFloat(float* value) OVERRIDE { |
| if (RandEvent(frequency_)) |
| *value = RandDouble(); |
| } |
| |
| virtual void FuzzDouble(double* value) OVERRIDE { |
| if (RandEvent(frequency_)) |
| *value = RandDouble(); |
| } |
| |
| virtual void FuzzString(std::string* value) OVERRIDE { |
| FuzzStringType<std::string>(value, frequency_, "BORKED", std::string()); |
| } |
| |
| virtual void FuzzString16(base::string16* value) OVERRIDE { |
| FuzzStringType<base::string16>(value, frequency_, |
| base::WideToUTF16(L"BORKED"), |
| base::WideToUTF16(L"")); |
| } |
| |
| virtual void FuzzData(char* data, int length) OVERRIDE { |
| if (RandEvent(frequency_)) { |
| for (int i = 0; i < length; ++i) { |
| FuzzIntegralType<char>(&data[i], frequency_); |
| } |
| } |
| } |
| |
| virtual void FuzzBytes(void* data, int data_len) OVERRIDE { |
| FuzzData(static_cast<char*>(data), data_len); |
| } |
| |
| private: |
| unsigned int frequency_; |
| }; |
| |
| |
| // No-op fuzzer. Rewrites each message unchanged to check if the message |
| // re-assembly is legit. |
| class NoOpFuzzer : public Fuzzer { |
| public: |
| NoOpFuzzer() {} |
| virtual ~NoOpFuzzer() {} |
| |
| virtual void FuzzBool(bool* value) OVERRIDE {} |
| virtual void FuzzInt(int* value) OVERRIDE {} |
| virtual void FuzzLong(long* value) OVERRIDE {} |
| virtual void FuzzSize(size_t* value) OVERRIDE {} |
| virtual void FuzzUChar(unsigned char* value) OVERRIDE {} |
| virtual void FuzzUInt16(uint16* value) OVERRIDE {} |
| virtual void FuzzUInt32(uint32* value) OVERRIDE {} |
| virtual void FuzzInt64(int64* value) OVERRIDE {} |
| virtual void FuzzUInt64(uint64* value) OVERRIDE {} |
| virtual void FuzzFloat(float* value) OVERRIDE {} |
| virtual void FuzzDouble(double* value) OVERRIDE {} |
| virtual void FuzzString(std::string* value) OVERRIDE {} |
| virtual void FuzzString16(base::string16* value) OVERRIDE {} |
| virtual void FuzzData(char* data, int length) OVERRIDE {} |
| virtual void FuzzBytes(void* data, int data_len) OVERRIDE {} |
| }; |
| |
| class FuzzerFactory { |
| public: |
| static Fuzzer *Create(const std::string& name, int frequency) { |
| if (name == "no-op") |
| return new NoOpFuzzer(); |
| |
| if (name == "default") |
| return new DefaultFuzzer(frequency); |
| |
| std::cerr << "No such fuzzer: " << name << "\n"; |
| return 0; |
| } |
| }; |
| |
| // Partially-specialized class that knows how to fuzz a given type. |
| template <class P> |
| struct FuzzTraits { |
| static void Fuzz(P* p, Fuzzer *fuzzer) { |
| // This is the catch-all for types we don't have enough information |
| // to fuzz. It simply does nothing to the type. We might want to |
| // change it to randomly flip a bit in the range (p, p+sizeof(P)). |
| } |
| }; |
| |
| // Template function to invoke partially-specialized class method. |
| template <class P> |
| static void FuzzParam(P* p, Fuzzer* fuzzer) { |
| FuzzTraits<P>::Fuzz(p, fuzzer); |
| } |
| |
| // Specializations to fuzz primitive types. |
| template <> |
| struct FuzzTraits<bool> { |
| static void Fuzz(bool* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzBool(p); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<int> { |
| static void Fuzz(int* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzInt(p); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<unsigned int> { |
| static void Fuzz(unsigned int* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzInt(reinterpret_cast<int*>(p)); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<long> { |
| static void Fuzz(long* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzLong(p); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<unsigned long> { |
| static void Fuzz(unsigned long* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzLong(reinterpret_cast<long*>(p)); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<long long> { |
| static void Fuzz(long long* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzInt64(reinterpret_cast<int64*>(p)); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<unsigned long long> { |
| static void Fuzz(unsigned long long* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzInt64(reinterpret_cast<int64*>(p)); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<short> { |
| static void Fuzz(short* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzUInt16(reinterpret_cast<uint16*>(p)); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<unsigned short> { |
| static void Fuzz(unsigned short* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzUInt16(reinterpret_cast<uint16*>(p)); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<char> { |
| static void Fuzz(char* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzUChar(reinterpret_cast<unsigned char*>(p)); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<unsigned char> { |
| static void Fuzz(unsigned char* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzUChar(p); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<float> { |
| static void Fuzz(float* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzFloat(p); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<double> { |
| static void Fuzz(double* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzDouble(p); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<std::string> { |
| static void Fuzz(std::string* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzString(p); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<base::string16> { |
| static void Fuzz(base::string16* p, Fuzzer* fuzzer) { |
| fuzzer->FuzzString16(p); |
| } |
| }; |
| |
| // Specializations to fuzz tuples. |
| template <class A> |
| struct FuzzTraits<Tuple1<A> > { |
| static void Fuzz(Tuple1<A>* p, Fuzzer* fuzzer) { |
| FuzzParam(&p->a, fuzzer); |
| } |
| }; |
| |
| template <class A, class B> |
| struct FuzzTraits<Tuple2<A, B> > { |
| static void Fuzz(Tuple2<A, B>* p, Fuzzer* fuzzer) { |
| FuzzParam(&p->a, fuzzer); |
| FuzzParam(&p->b, fuzzer); |
| } |
| }; |
| |
| template <class A, class B, class C> |
| struct FuzzTraits<Tuple3<A, B, C> > { |
| static void Fuzz(Tuple3<A, B, C>* p, Fuzzer* fuzzer) { |
| FuzzParam(&p->a, fuzzer); |
| FuzzParam(&p->b, fuzzer); |
| FuzzParam(&p->c, fuzzer); |
| } |
| }; |
| |
| template <class A, class B, class C, class D> |
| struct FuzzTraits<Tuple4<A, B, C, D> > { |
| static void Fuzz(Tuple4<A, B, C, D>* p, Fuzzer* fuzzer) { |
| FuzzParam(&p->a, fuzzer); |
| FuzzParam(&p->b, fuzzer); |
| FuzzParam(&p->c, fuzzer); |
| FuzzParam(&p->d, fuzzer); |
| } |
| }; |
| |
| template <class A, class B, class C, class D, class E> |
| struct FuzzTraits<Tuple5<A, B, C, D, E> > { |
| static void Fuzz(Tuple5<A, B, C, D, E>* p, Fuzzer* fuzzer) { |
| FuzzParam(&p->a, fuzzer); |
| FuzzParam(&p->b, fuzzer); |
| FuzzParam(&p->c, fuzzer); |
| FuzzParam(&p->d, fuzzer); |
| FuzzParam(&p->e, fuzzer); |
| } |
| }; |
| |
| // Specializations to fuzz containers. |
| template <class A> |
| struct FuzzTraits<std::vector<A> > { |
| static void Fuzz(std::vector<A>* p, Fuzzer* fuzzer) { |
| for (size_t i = 0; i < p->size(); ++i) { |
| FuzzParam(&p->at(i), fuzzer); |
| } |
| } |
| }; |
| |
| template <class A, class B> |
| struct FuzzTraits<std::map<A, B> > { |
| static void Fuzz(std::map<A, B>* p, Fuzzer* fuzzer) { |
| typename std::map<A, B>::iterator it; |
| for (it = p->begin(); it != p->end(); ++it) { |
| FuzzParam(&it->second, fuzzer); |
| } |
| } |
| }; |
| |
| template <class A, class B> |
| struct FuzzTraits<std::pair<A, B> > { |
| static void Fuzz(std::pair<A, B>* p, Fuzzer* fuzzer) { |
| FuzzParam(&p->second, fuzzer); |
| } |
| }; |
| |
| // Specializations to fuzz hand-coded tyoes |
| template <> |
| struct FuzzTraits<base::FileDescriptor> { |
| static void Fuzz(base::FileDescriptor* p, Fuzzer* fuzzer) { |
| FuzzParam(&p->fd, fuzzer); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<GURL> { |
| static void Fuzz(GURL *p, Fuzzer* fuzzer) { |
| FuzzParam(&p->possibly_invalid_spec(), fuzzer); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<gfx::Point> { |
| static void Fuzz(gfx::Point *p, Fuzzer* fuzzer) { |
| int x = p->x(); |
| int y = p->y(); |
| FuzzParam(&x, fuzzer); |
| FuzzParam(&y, fuzzer); |
| p->SetPoint(x, y); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<gfx::Size> { |
| static void Fuzz(gfx::Size *p, Fuzzer* fuzzer) { |
| int w = p->width(); |
| int h = p->height(); |
| FuzzParam(&w, fuzzer); |
| FuzzParam(&h, fuzzer); |
| p->SetSize(w, h); |
| } |
| }; |
| |
| template <> |
| struct FuzzTraits<gfx::Rect> { |
| static void Fuzz(gfx::Rect *p, Fuzzer* fuzzer) { |
| gfx::Point origin = p->origin(); |
| gfx::Size size = p->size(); |
| FuzzParam(&origin, fuzzer); |
| FuzzParam(&size, fuzzer); |
| p->set_origin(origin); |
| p->set_size(size); |
| } |
| }; |
| |
| // Redefine macros to generate fuzzing from traits declarations. |
| // Null out all the macros that need nulling. |
| #include "ipc/ipc_message_null_macros.h" |
| |
| // STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur. |
| #undef IPC_STRUCT_BEGIN |
| #undef IPC_STRUCT_BEGIN_WITH_PARENT |
| #undef IPC_STRUCT_MEMBER |
| #undef IPC_STRUCT_END |
| #define IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, parent) \ |
| IPC_STRUCT_BEGIN(struct_name) |
| #define IPC_STRUCT_BEGIN(struct_name) IPC_STRUCT_TRAITS_BEGIN(struct_name) |
| #define IPC_STRUCT_MEMBER(type, name, ...) IPC_STRUCT_TRAITS_MEMBER(name) |
| #define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END() |
| |
| // Set up so next include will generate fuzz trait classes. |
| #undef IPC_STRUCT_TRAITS_BEGIN |
| #undef IPC_STRUCT_TRAITS_MEMBER |
| #undef IPC_STRUCT_TRAITS_PARENT |
| #undef IPC_STRUCT_TRAITS_END |
| #define IPC_STRUCT_TRAITS_BEGIN(struct_name) \ |
| template <> \ |
| struct FuzzTraits<struct_name> { \ |
| static void Fuzz(struct_name *p, Fuzzer* fuzzer) { |
| |
| #define IPC_STRUCT_TRAITS_MEMBER(name) \ |
| FuzzParam(&p->name, fuzzer); |
| |
| #define IPC_STRUCT_TRAITS_PARENT(type) \ |
| FuzzParam(static_cast<type*>(p), fuzzer); |
| |
| #define IPC_STRUCT_TRAITS_END() \ |
| } \ |
| }; |
| |
| // TODO(tsepez): Make sure to end up with an enum that meets |condition|. |
| #undef IPC_ENUM_TRAITS_VALIDATE |
| #define IPC_ENUM_TRAITS_VALIDATE(enum_name, conditon) \ |
| template <> \ |
| struct FuzzTraits<enum_name> { \ |
| static void Fuzz(enum_name* p, Fuzzer* fuzzer) { \ |
| FuzzParam(reinterpret_cast<int*>(p), fuzzer); \ |
| } \ |
| }; |
| |
| // Bring them into existence. |
| #include "tools/ipc_fuzzer/message_lib/all_messages.h" |
| |
| // Redefine macros to generate fuzzing funtions |
| #include "ipc/ipc_message_null_macros.h" |
| #undef IPC_MESSAGE_DECL |
| #define IPC_MESSAGE_DECL(kind, type, name, in, out, ilist, olist) \ |
| IPC_##kind##_##type##_FUZZ(name, in, out, ilist, olist) |
| |
| #define IPC_EMPTY_CONTROL_FUZZ(name, in, out, ilist, olist) \ |
| IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) { \ |
| return NULL; \ |
| } |
| |
| #define IPC_EMPTY_ROUTED_FUZZ(name, in, out, ilist, olist) \ |
| IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) { \ |
| return NULL; \ |
| } |
| |
| #define IPC_ASYNC_CONTROL_FUZZ(name, in, out, ilist, olist) \ |
| IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) { \ |
| name* real_msg = static_cast<name*>(msg); \ |
| IPC_TUPLE_IN_##in ilist p; \ |
| name::Read(real_msg, &p); \ |
| FuzzParam(&p, fuzzer); \ |
| return new name(IPC_MEMBERS_IN_##in(p)); \ |
| } |
| |
| #define IPC_ASYNC_ROUTED_FUZZ(name, in, out, ilist, olist) \ |
| IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) { \ |
| name* real_msg = static_cast<name*>(msg); \ |
| IPC_TUPLE_IN_##in ilist p; \ |
| name::Read(real_msg, &p); \ |
| FuzzParam(&p, fuzzer); \ |
| return new name(msg->routing_id() \ |
| IPC_COMMA_##in \ |
| IPC_MEMBERS_IN_##in(p)); \ |
| } |
| |
| #define IPC_SYNC_CONTROL_FUZZ(name, in, out, ilist, olist) \ |
| IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) { \ |
| name* real_msg = static_cast<name*>(msg); \ |
| IPC_TUPLE_IN_##in ilist p; \ |
| name::ReadSendParam(real_msg, &p); \ |
| FuzzParam(&p, fuzzer); \ |
| name* new_msg = new name(IPC_MEMBERS_IN_##in(p) \ |
| IPC_COMMA_AND_##out(IPC_COMMA_##in) \ |
| IPC_MEMBERS_OUT_##out()); \ |
| MessageCracker::CopyMessageID(new_msg, real_msg); \ |
| return new_msg; \ |
| } |
| |
| |
| #define IPC_SYNC_ROUTED_FUZZ(name, in, out, ilist, olist) \ |
| IPC::Message* fuzzer_for_##name(IPC::Message *msg, Fuzzer* fuzzer) { \ |
| name* real_msg = static_cast<name*>(msg); \ |
| IPC_TUPLE_IN_##in ilist p; \ |
| name::ReadSendParam(real_msg, &p); \ |
| FuzzParam(&p, fuzzer); \ |
| name* new_msg = new name(msg->routing_id() \ |
| IPC_COMMA_OR_##out(IPC_COMMA_##in) \ |
| IPC_MEMBERS_IN_##in(p) \ |
| IPC_COMMA_AND_##out(IPC_COMMA_##in) \ |
| IPC_MEMBERS_OUT_##out()); \ |
| MessageCracker::CopyMessageID(new_msg, real_msg); \ |
| return new_msg; \ |
| } |
| |
| #define IPC_MEMBERS_IN_0(p) |
| #define IPC_MEMBERS_IN_1(p) p.a |
| #define IPC_MEMBERS_IN_2(p) p.a, p.b |
| #define IPC_MEMBERS_IN_3(p) p.a, p.b, p.c |
| #define IPC_MEMBERS_IN_4(p) p.a, p.b, p.c, p.d |
| #define IPC_MEMBERS_IN_5(p) p.a, p.b, p.c, p.d, p.e |
| |
| #define IPC_MEMBERS_OUT_0() |
| #define IPC_MEMBERS_OUT_1() NULL |
| #define IPC_MEMBERS_OUT_2() NULL, NULL |
| #define IPC_MEMBERS_OUT_3() NULL, NULL, NULL |
| #define IPC_MEMBERS_OUT_4() NULL, NULL, NULL, NULL |
| #define IPC_MEMBERS_OUT_5() NULL, NULL, NULL, NULL, NULL |
| |
| #include "tools/ipc_fuzzer/message_lib/all_messages.h" |
| |
| typedef IPC::Message* (*FuzzFunction)(IPC::Message*, Fuzzer*); |
| typedef base::hash_map<uint32, FuzzFunction> FuzzFunctionMap; |
| |
| // Redefine macros to register fuzzing functions into map. |
| #include "ipc/ipc_message_null_macros.h" |
| #undef IPC_MESSAGE_DECL |
| #define IPC_MESSAGE_DECL(kind, type, name, in, out, ilist, olist) \ |
| (*map)[static_cast<uint32>(name::ID)] = fuzzer_for_##name; |
| |
| void PopulateFuzzFunctionMap(FuzzFunctionMap *map) { |
| #include "tools/ipc_fuzzer/message_lib/all_messages.h" |
| } |
| |
| static IPC::Message* RewriteMessage( |
| IPC::Message* message, |
| Fuzzer* fuzzer, |
| FuzzFunctionMap* map) { |
| FuzzFunctionMap::iterator it = map->find(message->type()); |
| if (it == map->end()) { |
| // This usually indicates a missing message file in all_messages.h, or |
| // that the message dump file is taken from a different revision of |
| // chromium from this executable. |
| std::cerr << "Unknown message type: [" |
| << IPC_MESSAGE_ID_CLASS(message->type()) << ", " |
| << IPC_MESSAGE_ID_LINE(message->type()) << "].\n"; |
| return 0; |
| } |
| |
| return (*it->second)(message, fuzzer); |
| } |
| |
| namespace { |
| |
| const char kHelpSwitch[] = "help"; |
| const char kHelpSwitchHelp[] = |
| "show this message"; |
| |
| const char kFrequencySwitch[] = "frequency"; |
| const char kFrequencySwitchHelp[] = |
| "probability of mutation; tweak every 1/|q| times."; |
| |
| const char kFuzzerNameSwitch[] = "fuzzer-name"; |
| const char kFuzzerNameSwitchHelp[] = |
| "select default or no-op fuzzer."; |
| |
| const char kPermuteSwitch[] = "permute"; |
| const char kPermuteSwitchHelp[] = |
| "Randomly shuffle the order of all messages."; |
| |
| const char kTypeListSwitch[] = "type-list"; |
| const char kTypeListSwitchHelp[] = |
| "explicit list of the only message-ids to mutate."; |
| |
| void usage() { |
| std::cerr << "Mutate messages from an exiting message file.\n"; |
| |
| std::cerr << "Usage:\n" |
| << " ipc_fuzzer_mutate" |
| << " [--" << kHelpSwitch << "]" |
| << " [--" << kFuzzerNameSwitch << "=f]" |
| << " [--" << kFrequencySwitch << "=q]" |
| << " [--" << kTypeListSwitch << "=x,y,z...]" |
| << " [--" << kPermuteSwitch << "]" |
| << " infile outfile\n"; |
| |
| std::cerr |
| << " --" << kHelpSwitch << " - " << kHelpSwitchHelp << "\n" |
| << " --" << kFuzzerNameSwitch << " - " << kFuzzerNameSwitchHelp << "\n" |
| << " --" << kFrequencySwitch << " - " << kFrequencySwitchHelp << "\n" |
| << " --" << kTypeListSwitch << " - " << kTypeListSwitchHelp << "\n" |
| << " --" << kPermuteSwitch << " - " << kPermuteSwitchHelp << "\n"; |
| } |
| |
| } // namespace |
| |
| int MutateMain(int argc, char** argv) { |
| CommandLine::Init(argc, argv); |
| CommandLine* cmd = CommandLine::ForCurrentProcess(); |
| CommandLine::StringVector args = cmd->GetArgs(); |
| |
| if (args.size() != 2 || cmd->HasSwitch(kHelpSwitch)) { |
| usage(); |
| return EXIT_FAILURE; |
| } |
| |
| std::string input_file_name = args[0]; |
| std::string output_file_name = args[1]; |
| |
| bool permute = cmd->HasSwitch(kPermuteSwitch); |
| |
| std::string fuzzer_name = "default"; |
| if (cmd->HasSwitch(kFuzzerNameSwitch)) |
| fuzzer_name = cmd->GetSwitchValueASCII(kFuzzerNameSwitch); |
| |
| int frequency = 23; |
| if (cmd->HasSwitch(kFrequencySwitch)) |
| frequency = atoi(cmd->GetSwitchValueASCII(kFrequencySwitch).c_str()); |
| |
| std::string type_string_list = cmd->GetSwitchValueASCII(kTypeListSwitch); |
| std::vector<std::string> type_string_vector; |
| base::SplitString(type_string_list, ',', &type_string_vector); |
| std::set<int> type_set; |
| for (size_t i = 0; i < type_string_vector.size(); ++i) { |
| type_set.insert(atoi(type_string_vector[i].c_str())); |
| } |
| |
| InitRand(); |
| |
| Fuzzer* fuzzer = FuzzerFactory::Create(fuzzer_name, frequency); |
| if (!fuzzer) |
| return EXIT_FAILURE; |
| |
| FuzzFunctionMap fuzz_function_map; |
| PopulateFuzzFunctionMap(&fuzz_function_map); |
| |
| MessageVector message_vector; |
| if (!MessageFile::Read(base::FilePath(input_file_name), &message_vector)) |
| return EXIT_FAILURE; |
| |
| for (size_t i = 0; i < message_vector.size(); ++i) { |
| IPC::Message* msg = message_vector[i]; |
| if (!type_set.empty() && type_set.end() == std::find( |
| type_set.begin(), type_set.end(), msg->type())) { |
| continue; |
| } |
| IPC::Message* new_message = RewriteMessage(msg, fuzzer, &fuzz_function_map); |
| if (new_message) { |
| delete message_vector[i]; |
| message_vector[i] = new_message; |
| } |
| } |
| |
| if (permute) { |
| std::random_shuffle(message_vector.begin(), message_vector.end(), |
| RandInRange); |
| } |
| |
| if (!MessageFile::Write(base::FilePath(output_file_name), message_vector)) |
| return EXIT_FAILURE; |
| |
| return EXIT_SUCCESS; |
| } |
| |
| } // namespace ipc_fuzzer |
| |
| int main(int argc, char** argv) { |
| return ipc_fuzzer::MutateMain(argc, argv); |
| } |