// Copyright (c) 2011 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 #include #include #include #include "base/command_line.h" #include "base/hash_tables.h" #include "base/memory/scoped_ptr.h" #include "base/memory/singleton.h" #include "base/message_loop.h" #include "base/pickle.h" #include "base/process_util.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/threading/thread.h" #include "base/time.h" #include "base/utf_string_conversions.h" #include "chrome/common/all_messages.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" #if defined(OS_POSIX) #include #endif namespace IPC { class Message; // 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: // Select a message for fuzzing. virtual bool FuzzThisMessage(const IPC::Message *msg) = 0; // 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 FuzzWString(std::wstring* value) = 0; virtual void FuzzString16(string16* value) = 0; virtual void FuzzData(char* data, int length) = 0; virtual void FuzzBytes(void* data, int data_len) = 0; }; } // namespace IPC namespace { template void FuzzIntegralType(T* value, unsigned int frequency) { if (rand() % frequency == 0) { switch (rand() % 4) { case 0: (*value) = 0; break; case 1: (*value)--; break; case 2: (*value)++; break; case 3: (*value) ^= rand(); break; } } } template void FuzzStringType(T* value, unsigned int frequency, const T& literal1, const T& literal2) { if (rand() % frequency == 0) { switch (rand() % 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; } } } } // namespace // One such fuzzer implementation. class DefaultFuzzer : public IPC::Fuzzer { public: static const int DEFAULT_FREQUENCY = 23; DefaultFuzzer() : frequency_(DEFAULT_FREQUENCY) { const char *env_var; if ((env_var = getenv("CHROME_IPC_FUZZING_LIST"))) { std::string str = std::string(env_var); size_t pos; while ((pos = str.find_first_of(',')) != std::string::npos) { message_set_.insert(atoi(str.substr(0, pos).c_str())); str = str.substr(pos+1); } message_set_.insert(atoi(str.c_str())); } if ((env_var = getenv("CHROME_IPC_FUZZING_SEED"))) { int new_seed = atoi(env_var); if (new_seed) srand(new_seed); } if ((env_var = getenv("CHROME_IPC_FUZZING_FREQUENCY"))) { unsigned int new_frequency = atoi(env_var); if (new_frequency) frequency_ = new_frequency; } } virtual ~DefaultFuzzer() {} virtual bool FuzzThisMessage(const IPC::Message *msg) { return (message_set_.empty() || std::find(message_set_.begin(), message_set_.end(), msg->type()) != message_set_.end()); } virtual void FuzzBool(bool* value) { if (rand() % frequency_ == 0) (*value) = !(*value); } virtual void FuzzInt(int* value) { FuzzIntegralType(value, frequency_); } virtual void FuzzLong(long* value) { FuzzIntegralType(value, frequency_); } virtual void FuzzSize(size_t* value) { FuzzIntegralType(value, frequency_); } virtual void FuzzUChar(unsigned char* value) { FuzzIntegralType(value, frequency_); } virtual void FuzzUInt16(uint16* value) { FuzzIntegralType(value, frequency_); } virtual void FuzzUInt32(uint32* value) { FuzzIntegralType(value, frequency_); } virtual void FuzzInt64(int64* value) { FuzzIntegralType(value, frequency_); } virtual void FuzzUInt64(uint64* value) { FuzzIntegralType(value, frequency_); } virtual void FuzzFloat(float* value) { if (rand() % frequency_ == 0) (*value) *= rand() / 1000000.0; } virtual void FuzzDouble(double* value) { if (rand() % frequency_ == 0) (*value) *= rand() / 1000000.0; } virtual void FuzzString(std::string* value) { FuzzStringType(value, frequency_, "BORKED", ""); } virtual void FuzzWString(std::wstring* value) { FuzzStringType(value, frequency_, L"BORKED", L""); } virtual void FuzzString16(string16* value) { FuzzStringType(value, frequency_, WideToUTF16(L"BORKED"), WideToUTF16(L"")); } virtual void FuzzData(char* data, int length) { if (rand() % frequency_ == 0) { for (int i = 0; i < length; ++i) { FuzzIntegralType(&data[i], frequency_); } } } virtual void FuzzBytes(void* data, int data_len) { FuzzData(static_cast(data), data_len); } private: std::set message_set_; unsigned int frequency_; }; // No-op fuzzer. Rewrites each message unchanged to check if the message // re-assembly is legit. class NoOpFuzzer : public IPC::Fuzzer { public: NoOpFuzzer() {} virtual ~NoOpFuzzer() {} virtual bool FuzzThisMessage(const IPC::Message *msg) { return true; } virtual void FuzzBool(bool* value) {} virtual void FuzzInt(int* value) {} virtual void FuzzLong(long* value) {} virtual void FuzzSize(size_t* value) {} virtual void FuzzUChar(unsigned char* value) {} virtual void FuzzUInt16(uint16* value) {} virtual void FuzzUInt32(uint32* value) {} virtual void FuzzInt64(int64* value) {} virtual void FuzzUInt64(uint64* value) {} virtual void FuzzFloat(float* value) {} virtual void FuzzDouble(double* value) {} virtual void FuzzString(std::string* value) {} virtual void FuzzWString(std::wstring* value) {} virtual void FuzzString16(string16* value) {} virtual void FuzzData(char* data, int length) {} virtual void FuzzBytes(void* data, int data_len) {} }; class FuzzerFactory { public: static IPC::Fuzzer *NewFuzzer(const std::string& name) { if (name == "no-op") return new NoOpFuzzer(); else return new DefaultFuzzer(); } }; // Partially-specialized class that knows how to fuzz a given type. template struct FuzzTraits { static void Fuzz(P* p, IPC::Fuzzer *fuzzer) {} }; // Template function to invoke partially-specialized class method. template static void FuzzParam(P* p, IPC::Fuzzer* fuzzer) { FuzzTraits

::Fuzz(p, fuzzer); } // Specializations to fuzz primitive types. template <> struct FuzzTraits { static void Fuzz(bool* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzBool(p); } }; template <> struct FuzzTraits { static void Fuzz(int* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzInt(p); } }; template <> struct FuzzTraits { static void Fuzz(unsigned int* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzInt(reinterpret_cast(p)); } }; template <> struct FuzzTraits { static void Fuzz(long* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzLong(p); } }; template <> struct FuzzTraits { static void Fuzz(unsigned long* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzLong(reinterpret_cast(p)); } }; template <> struct FuzzTraits { static void Fuzz(long long* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzInt64(reinterpret_cast(p)); } }; template <> struct FuzzTraits { static void Fuzz(unsigned long long* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzInt64(reinterpret_cast(p)); } }; template <> struct FuzzTraits { static void Fuzz(short* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzUInt16(reinterpret_cast(p)); } }; template <> struct FuzzTraits { static void Fuzz(unsigned short* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzUInt16(reinterpret_cast(p)); } }; template <> struct FuzzTraits { static void Fuzz(char* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzUChar(reinterpret_cast(p)); } }; template <> struct FuzzTraits { static void Fuzz(unsigned char* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzUChar(p); } }; template <> struct FuzzTraits { static void Fuzz(float* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzFloat(p); } }; template <> struct FuzzTraits { static void Fuzz(double* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzDouble(p); } }; template <> struct FuzzTraits { static void Fuzz(std::string* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzString(p); } }; template <> struct FuzzTraits { static void Fuzz(std::wstring* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzWString(p); } }; template <> struct FuzzTraits { static void Fuzz(string16* p, IPC::Fuzzer* fuzzer) { fuzzer->FuzzString16(p); } }; // Specializations to fuzz tuples. template struct FuzzTraits > { static void Fuzz(Tuple1* p, IPC::Fuzzer* fuzzer) { FuzzParam(&p->a, fuzzer); } }; template struct FuzzTraits > { static void Fuzz(Tuple2* p, IPC::Fuzzer* fuzzer) { FuzzParam(&p->a, fuzzer); FuzzParam(&p->b, fuzzer); } }; template struct FuzzTraits > { static void Fuzz(Tuple3* p, IPC::Fuzzer* fuzzer) { FuzzParam(&p->a, fuzzer); FuzzParam(&p->b, fuzzer); FuzzParam(&p->c, fuzzer); } }; template struct FuzzTraits > { static void Fuzz(Tuple4* p, IPC::Fuzzer* fuzzer) { FuzzParam(&p->a, fuzzer); FuzzParam(&p->b, fuzzer); FuzzParam(&p->c, fuzzer); FuzzParam(&p->d, fuzzer); } }; template struct FuzzTraits > { static void Fuzz(Tuple5* p, IPC::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 struct FuzzTraits > { static void Fuzz(std::vector* p, IPC::Fuzzer* fuzzer) { for (size_t i = 0; i < p->size(); ++i) { FuzzParam(&p->at(i), fuzzer); } } }; template struct FuzzTraits > { static void Fuzz(std::map* p, IPC::Fuzzer* fuzzer) { typename std::map::iterator it; for (it = p->begin(); it != p->end(); ++it) { FuzzParam(&it->second, fuzzer); } } }; template struct FuzzTraits > { static void Fuzz(std::pair* p, IPC::Fuzzer* fuzzer) { FuzzParam(&p->second, fuzzer); } }; // Specializations to fuzz hand-coded tyoes template <> struct FuzzTraits { static void Fuzz(base::FileDescriptor* p, IPC::Fuzzer* fuzzer) { FuzzParam(&p->fd, fuzzer); } }; template <> struct FuzzTraits { static void Fuzz(GURL *p, IPC::Fuzzer* fuzzer) { FuzzParam(&p->possibly_invalid_spec(), fuzzer); } }; template <> struct FuzzTraits { static void Fuzz(gfx::Point *p, IPC::Fuzzer* fuzzer) { int x = p->x(); int y = p->y(); FuzzParam(&x, fuzzer); FuzzParam(&y, fuzzer); p->SetPoint(x, y); } }; template <> struct FuzzTraits { static void Fuzz(gfx::Size *p, IPC::Fuzzer* fuzzer) { int w = p->width(); int h = p->height(); FuzzParam(&w, fuzzer); FuzzParam(&h, fuzzer); p->SetSize(w, h); } }; template <> struct FuzzTraits { static void Fuzz(gfx::Rect *p, IPC::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); } }; // Means for updating message id in pickles. class PickleCracker : public Pickle { public: static void CopyMessageID(PickleCracker *dst, PickleCracker *src) { memcpy(dst->payload(), src->payload(), sizeof(int)); } }; // 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 { \ static void Fuzz(struct_name *p, IPC::Fuzzer* fuzzer) { \ #define IPC_STRUCT_TRAITS_MEMBER(name) \ FuzzParam(&p->name, fuzzer); #define IPC_STRUCT_TRAITS_PARENT(type) \ FuzzParam(static_cast(p), fuzzer); #define IPC_STRUCT_TRAITS_END() \ } \ }; #undef IPC_ENUM_TRAITS #define IPC_ENUM_TRAITS(enum_name) \ template <> \ struct FuzzTraits { \ static void Fuzz(enum_name* p, IPC::Fuzzer* fuzzer) { \ FuzzParam(reinterpret_cast(p), fuzzer); \ } \ }; // Bring them into existence. #include "chrome/common/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, IPC::Fuzzer* fuzzer) { \ return NULL; \ } #define IPC_EMPTY_ROUTED_FUZZ(name, in, out, ilist, olist) \ IPC::Message* fuzzer_for_##name(IPC::Message *msg, IPC::Fuzzer* fuzzer) { \ return NULL; \ } #define IPC_ASYNC_CONTROL_FUZZ(name, in, out, ilist, olist) \ IPC::Message* fuzzer_for_##name(IPC::Message *msg, IPC::Fuzzer* fuzzer) { \ name* real_msg = static_cast(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, IPC::Fuzzer* fuzzer) { \ name* real_msg = static_cast(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, IPC::Fuzzer* fuzzer) { \ name* real_msg = static_cast(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()); \ PickleCracker::CopyMessageID( \ reinterpret_cast(new_msg), \ reinterpret_cast(real_msg)); \ return new_msg; \ } #define IPC_SYNC_ROUTED_FUZZ(name, in, out, ilist, olist) \ IPC::Message* fuzzer_for_##name(IPC::Message *msg, IPC::Fuzzer* fuzzer) { \ name* real_msg = static_cast(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()); \ PickleCracker::CopyMessageID( \ reinterpret_cast(new_msg), \ reinterpret_cast(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 "chrome/common/all_messages.h" typedef IPC::Message* (*FuzzFunction)(IPC::Message*, IPC::Fuzzer*); typedef base::hash_map 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(name::ID)] = fuzzer_for_##name; void PopulateFuzzFunctionMap(FuzzFunctionMap *map) { #include "chrome/common/all_messages.h" } class ipcfuzz : public IPC::ChannelProxy::OutgoingMessageFilter { public: ipcfuzz() { const char* env_var = getenv("CHROME_IPC_FUZZING_KIND"); fuzzer_ = FuzzerFactory::NewFuzzer(env_var ? env_var : ""); PopulateFuzzFunctionMap(&fuzz_function_map_); } IPC::Message* Rewrite(IPC::Message* message) { if (fuzzer_ && fuzzer_->FuzzThisMessage(message)) { FuzzFunctionMap::iterator it = fuzz_function_map_.find(message->type()); if (it != fuzz_function_map_.end()) { IPC::Message* fuzzed_message = (*it->second)(message, fuzzer_); if (fuzzed_message) { delete message; message = fuzzed_message; } } } return message; } private: IPC::Fuzzer* fuzzer_; FuzzFunctionMap fuzz_function_map_; }; ipcfuzz g_ipcfuzz; // Entry point avoiding mangled names. extern "C" { __attribute__((visibility("default"))) IPC::ChannelProxy::OutgoingMessageFilter* GetFilter(void); } IPC::ChannelProxy::OutgoingMessageFilter* GetFilter(void) { return &g_ipcfuzz; }