Bug 777067 - Fuzzing: IPC Protocol Definition Language (IPDL) Protocols. r=jld
authorChristoph Diehl <cdiehl@mozilla.com>
Tue, 24 Apr 2018 20:10:15 +0200
changeset 471589 44e4fec63d98c64f71591f93d6ee13c00e75ad64
parent 471588 9a092f00fdd698ea9b3f705dcea9e32b9979fb28
child 471590 3ad3cb5e9b6579da19baa654cbde058f5b45a997
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjld
bugs777067
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 777067 - Fuzzing: IPC Protocol Definition Language (IPDL) Protocols. r=jld
ipc/chromium/src/base/pickle.cc
ipc/chromium/src/chrome/common/ipc_channel_posix.cc
ipc/chromium/src/chrome/common/ipc_message.h
ipc/glue/Faulty.cpp
ipc/glue/Faulty.h
ipc/glue/moz.build
tools/fuzzing/faulty/Faulty.cpp
tools/fuzzing/faulty/Faulty.h
tools/fuzzing/faulty/moz.build
tools/fuzzing/moz.build
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -680,23 +680,17 @@ bool Pickle::WriteWString(const std::wst
     return false;
 
   return WriteBytes(value.data(),
                     static_cast<int>(value.size() * sizeof(wchar_t)));
 #endif
 }
 
 bool Pickle::WriteData(const char* data, uint32_t length) {
-#ifdef FUZZING
-  std::string v(data, length);
-  Singleton<mozilla::ipc::Faulty>::get()->FuzzData(v, v.size());
-  return WriteInt(v.size()) && WriteBytes(v.data(), v.size());
-#else
    return WriteInt(length) && WriteBytes(data, length);
-#endif
 }
 
 void Pickle::InputBytes(const char* data, uint32_t length) {
   buffers_.WriteBytes(data, length);
 }
 
 int32_t* Pickle::GetInt32PtrForTest(uint32_t offset) {
   size_t pos = buffers_.Size() - offset;
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -749,16 +749,19 @@ bool Channel::ChannelImpl::ProcessOutgoi
 
 bool Channel::ChannelImpl::Send(Message* message) {
 #ifdef IPC_MESSAGE_DEBUG_EXTRA
   DLOG(INFO) << "sending message @" << message << " on channel @" << this
              << " with type " << message->type()
              << " (" << output_queue_.size() << " in queue)";
 #endif
 
+#ifdef FUZZING
+  message = Singleton<mozilla::ipc::Faulty>::get()->MutateIPCMessage("Channel::ChannelImpl::Send", message);
+#endif
 
   // If the channel has been closed, ProcessOutgoingMessages() is never going
   // to pop anything off output_queue; output_queue will only get emptied when
   // the channel is destructed.  We might as well delete message now, instead
   // of waiting for the channel to be destructed.
   if (closed_) {
     if (mozilla::ipc::LoggingEnabled()) {
       fprintf(stderr, "Can't send message %s, because this channel is closed.\n",
--- a/ipc/chromium/src/chrome/common/ipc_message.h
+++ b/ipc/chromium/src/chrome/common/ipc_message.h
@@ -16,31 +16,38 @@
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #endif
 
 #if defined(OS_POSIX)
 #include "nsAutoPtr.h"
 #endif
 
+#ifdef FUZZING
+#include "mozilla/ipc/Faulty.h"
+#endif
+
 namespace base {
 struct FileDescriptor;
 }
 
 class FileDescriptorSet;
 
 namespace IPC {
 
 //------------------------------------------------------------------------------
 
 // Generated by IPDL compiler
 const char* StringFromIPCMessageType(uint32_t aMessageType);
 
 class Channel;
 class Message;
+#ifdef FUZZING
+class Faulty;
+#endif
 struct LogData;
 
 class Message : public Pickle {
  public:
   typedef uint32_t msgid_t;
 
   enum NestedLevel {
     NOT_NESTED = 1,
@@ -378,16 +385,19 @@ class Message : public Pickle {
   }
 #endif
 #endif
 
 
   friend class Channel;
   friend class MessageReplyDeserializer;
   friend class SyncMessage;
+#ifdef FUZZING
+  friend class mozilla::ipc::Faulty;
+#endif
 
 #ifdef MOZ_TASK_TRACER
   void TaskTracerDispatch();
   class AutoTaskTracerRun
     : public mozilla::tasktracer::AutoSaveCurTraceInfo {
     Message& mMsg;
     uint64_t mTaskId;
     uint64_t mSourceEventId;
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -44,20 +44,16 @@ EXPORTS.mozilla.ipc += [
     'SharedMemoryBasic.h',
     'Shmem.h',
     'TaskFactory.h',
     'Transport.h',
     'URIUtils.h',
     'WindowsMessageLoop.h',
 ]
 
-if CONFIG['FUZZING'] == '1':
-    EXPORTS.mozilla.ipc += ['Faulty.h']
-    SOURCES += ['Faulty.cpp']
-
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXPORTS.mozilla.ipc += [
         'Transport_win.h',
     ]
     SOURCES += [
         'SharedMemory_windows.cpp',
         'Transport_win.cpp',
         'WindowsMessageLoop.cpp',
rename from ipc/glue/Faulty.cpp
rename to tools/fuzzing/faulty/Faulty.cpp
--- a/ipc/glue/Faulty.cpp
+++ b/tools/fuzzing/faulty/Faulty.cpp
@@ -2,29 +2,43 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <cerrno>
 #include <climits>
 #include <cmath>
+#include <fstream>
 #include <prinrval.h>
 #include <unistd.h>
 #include "base/string_util.h"
+#include "FuzzingMutate.h"
+#include "FuzzingTraits.h"
+#include "chrome/common/ipc_channel.h"
 #include "chrome/common/ipc_message.h"
-#include "chrome/common/ipc_channel.h"
+#include "chrome/common/file_descriptor_set_posix.h"
 #include "mozilla/ipc/Faulty.h"
 #include "mozilla/TypeTraits.h"
+#include "nsNetCID.h"
+#include "nsIFile.h"
+#include "nsIFileStreams.h"
+#include "nsILineInputStream.h"
+#include "nsLocalFile.h"
+#include "nsPrintfCString.h"
+#include "nsTArray.h"
 #include "nsXULAppAPI.h"
 #include "prenv.h"
 
+
 namespace mozilla {
 namespace ipc {
 
+using namespace mozilla::fuzzing;
+
 const unsigned int Faulty::sDefaultProbability = Faulty::DefaultProbability();
 const bool Faulty::sIsLoggingEnabled = Faulty::Logging();
 
 /**
  * RandomNumericValue generates negative and positive integrals.
  */
 template <typename T>
 T RandomIntegral()
@@ -55,17 +69,17 @@ T RandomNumericLimit() {
  * RandomIntegerRange returns a random integral within a user defined range.
  */
 template <typename T>
 T RandomIntegerRange(T min, T max)
 {
   static_assert(mozilla::IsIntegral<T>::value == true,
                 "T must be an integral type");
   MOZ_ASSERT(min < max);
-  return static_cast<T>(random() % (max - min) + min);
+  return static_cast<T>((random() % (max - min + 1)) + min);
 }
 
 /**
  * RandomFloatingPointRange returns a random floating-point number within a
  * user defined range.
  */
 template <typename T>
 T RandomFloatingPointRange(T min, T max)
@@ -83,61 +97,55 @@ T RandomFloatingPointRange(T min, T max)
 template <typename T>
 T RandomFloatingPoint()
 {
   static_assert(mozilla::IsFloatingPoint<T>::value == true,
                 "T must be a floating point type");
   int radix = RandomIntegerRange<int>(std::numeric_limits<T>::min_exponent,
                                       std::numeric_limits<T>::max_exponent);
   T x = static_cast<T>(pow(2.0, static_cast<double>(radix)));
-  return x * RandomFloatingPointRange<T>(1.0, 2.0);
+  return x * RandomFloatingPointRange<T>(0.0, 10.0);
 }
 
 /**
  * FuzzIntegralType mutates an incercepted integral type of a pickled message.
  */
 template <typename T>
 void FuzzIntegralType(T* v, bool largeValues)
 {
   static_assert(mozilla::IsIntegral<T>::value == true,
                 "T must be an integral type");
   switch (random() % 6) {
     case 0:
       if (largeValues) {
         (*v) = RandomIntegral<T>();
         break;
       }
-      // Fall through
       MOZ_FALLTHROUGH;
-
     case 1:
       if (largeValues) {
         (*v) = RandomNumericLimit<T>();
         break;
       }
-      // Fall through
       MOZ_FALLTHROUGH;
-
     case 2:
       if (largeValues) {
         (*v) = RandomIntegerRange<T>(std::numeric_limits<T>::min(),
                                      std::numeric_limits<T>::max());
         break;
       }
-      // Fall through
       MOZ_FALLTHROUGH;
     default:
       switch(random() % 2) {
         case 0:
           // Prevent underflow
           if (*v != std::numeric_limits<T>::min()) {
             (*v)--;
             break;
           }
-          // Fall through
           MOZ_FALLTHROUGH;
         case 1:
           // Prevent overflow
           if (*v != std::numeric_limits<T>::max()) {
             (*v)++;
             break;
           }
       }
@@ -154,111 +162,143 @@ void FuzzFloatingPointType(T* v, bool la
   static_assert(mozilla::IsFloatingPoint<T>::value == true,
                 "T must be a floating point type");
   switch (random() % 6) {
     case 0:
       if (largeValues) {
         (*v) = RandomNumericLimit<T>();
         break;
     }
-    // Fall through
     MOZ_FALLTHROUGH;
     case 1:
       if (largeValues) {
         (*v) = RandomFloatingPointRange<T>(std::numeric_limits<T>::min(),
                                            std::numeric_limits<T>::max());
         break;
       }
-    // Fall through
     MOZ_FALLTHROUGH;
     default:
       (*v) = RandomFloatingPoint<T>();
   }
 }
 
 /**
  * FuzzStringType mutates an incercepted string type of a pickled message.
  */
 template <typename T>
 void FuzzStringType(T& v, const T& literal1, const T& literal2)
 {
   switch (random() % 5) {
     case 4:
       v = v + v;
-      // Fall through
       MOZ_FALLTHROUGH;
     case 3:
       v = v + v;
-      // Fall through
       MOZ_FALLTHROUGH;
     case 2:
       v = v + v;
       break;
     case 1:
       v += literal1;
       break;
     case 0:
       v = literal2;
       break;
   }
 }
 
 
 Faulty::Faulty()
+  // Mutate messages as a blob.
+  : mFuzzMessages(!!PR_GetEnv("FAULTY_MESSAGES"))
   // Enables the strategy for fuzzing pipes.
-  : mFuzzPipes(!!PR_GetEnv("FAULTY_PIPE"))
+  , mFuzzPipes(!!PR_GetEnv("FAULTY_PIPE"))
   // Enables the strategy for fuzzing pickled messages.
   , mFuzzPickle(!!PR_GetEnv("FAULTY_PICKLE"))
   // Uses very large values while fuzzing pickled messages.
   // This may cause a high amount of malloc_abort() / NS_ABORT_OOM crashes.
   , mUseLargeValues(!!PR_GetEnv("FAULTY_LARGE_VALUES"))
+  // Use the provided blacklist as whitelist.
+  , mUseAsWhitelist(!!PR_GetEnv("FAULTY_AS_WHITELIST"))
   // Sets up our target process.
   , mIsValidProcessType(IsValidProcessType())
 {
-  FAULTY_LOG("Initializing.");
+  if (mIsValidProcessType) {
+    FAULTY_LOG("Initializing for new process of type '%s' with pid %u.",
+      XRE_ChildProcessTypeToString(XRE_GetProcessType()),
+      getpid());
+
+    /* Setup random seed. */
+    const char* userSeed = PR_GetEnv("FAULTY_SEED");
+    unsigned long randomSeed = static_cast<unsigned long>(PR_IntervalNow());
+    if (userSeed) {
+      long n = std::strtol(userSeed, nullptr, 10);
+      if (n != 0) {
+        randomSeed = static_cast<unsigned long>(n);
+      }
+    }
+    srandom(randomSeed);
 
-  const char* userSeed = PR_GetEnv("FAULTY_SEED");
-  unsigned long randomSeed = static_cast<unsigned long>(PR_IntervalNow());
-  if (userSeed) {
-    long n = std::strtol(userSeed, nullptr, 10);
-    if (n != 0) {
-      randomSeed = static_cast<unsigned long>(n);
+    /* Setup directory for dumping messages. */
+    mMessagePath = PR_GetEnv("FAULTY_MESSAGE_PATH");
+    if (mMessagePath && *mMessagePath) {
+      if (CreateOutputDirectory(mMessagePath) != NS_OK) {
+        mMessagePath = nullptr;
+      }
     }
-  }
-  srandom(randomSeed);
+
+    /* Set IPC messages blacklist. */
+    mBlacklistPath = PR_GetEnv("FAULTY_BLACKLIST");
+    if (mBlacklistPath && *mBlacklistPath) {
+      FAULTY_LOG("* Using message blacklist    = %s", mBlacklistPath);
+    }
 
-  FAULTY_LOG("Fuzz probability = %u", sDefaultProbability);
-  FAULTY_LOG("Random seed      = %lu", randomSeed);
-  FAULTY_LOG("Strategy: pickle = %s", mFuzzPickle ? "enabled" : "disabled");
-  FAULTY_LOG("Strategy: pipe   = %s", mFuzzPipes ? "enabled" : "disabled");
+    FAULTY_LOG("* Fuzzing strategy: messages = %s", mFuzzMessages ? "enabled" : "disabled");
+    FAULTY_LOG("* Fuzzing strategy: pickle   = %s", mFuzzPickle ? "enabled" : "disabled");
+    FAULTY_LOG("* Fuzzing strategy: pipe     = %s", mFuzzPipes ? "enabled" : "disabled");
+    FAULTY_LOG("* Fuzzing probability        = %u", sDefaultProbability);
+    FAULTY_LOG("* Fuzzing mutation factor    = %u", MutationFactor());
+    FAULTY_LOG("* RNG seed                   = %lu", randomSeed);
+
+    sMsgCounter = 0;
+  }
 }
 
 // static
 bool
 Faulty::IsValidProcessType(void)
 {
   bool isValidProcessType;
   const bool targetChildren = !!PR_GetEnv("FAULTY_CHILDREN");
   const bool targetParent = !!PR_GetEnv("FAULTY_PARENT");
+  unsigned short int currentProcessType = XRE_GetProcessType();
 
   if (targetChildren && !targetParent) {
-    // Fuzz every process type but not the content process.
-    isValidProcessType = XRE_GetProcessType() != GeckoProcessType_Content;
+    // Fuzz every child process type but not the parent process.
+    isValidProcessType = currentProcessType == GeckoProcessType_Default;
+  } else if (!targetChildren && targetParent
+          && (currentProcessType == GeckoProcessType_Plugin
+          || currentProcessType == GeckoProcessType_Content
+          || currentProcessType == GeckoProcessType_GMPlugin
+          || currentProcessType == GeckoProcessType_GPU
+          || currentProcessType == GeckoProcessType_PDFium)) {
+    // Fuzz inside any of the above child process only.
+    isValidProcessType = true;
   } else if (targetChildren && targetParent) {
     // Fuzz every process type.
     isValidProcessType = true;
   } else {
-    // Fuzz the content process only.
-    isValidProcessType = XRE_GetProcessType() == GeckoProcessType_Content;
+    // Fuzz no process type at all.
+    isValidProcessType = false;
   }
 
-  // Parent and children are different threads in the same process on
-  // desktop builds.
   if (!isValidProcessType) {
-    FAULTY_LOG("Invalid process type for pid=%d", getpid());
+    FAULTY_LOG("Disabled for this process of type '%s' with pid %d.",
+      XRE_ChildProcessTypeToString(XRE_GetProcessType()),
+      getpid());
   }
 
   return isValidProcessType;
 }
 
 // static
 unsigned int
 Faulty::DefaultProbability(void)
@@ -277,55 +317,66 @@ Faulty::DefaultProbability(void)
 // static
 bool
 Faulty::Logging(void)
 {
   // Enables logging of sendmsg() calls even in optimized builds.
   return !!PR_GetEnv("FAULTY_ENABLE_LOGGING");
 }
 
-unsigned int
-Faulty::Random(unsigned int aMax)
+
+// static
+uint32_t
+Faulty::MutationFactor()
 {
-  MOZ_ASSERT(aMax > 0);
-  return static_cast<unsigned int>(random() % aMax);
-}
+  static uint64_t sPropValue = FAULTY_DEFAULT_MUTATION_FACTOR;
+  static bool sInitialized = false;
+
+  if (sInitialized) {
+    return sPropValue;
+  }
+  sInitialized = true;
 
-bool
-Faulty::GetChance(unsigned int aProbability)
-{
-  return Random(aProbability) == 0;
+  const char* factor = PR_GetEnv("FAULTY_MUTATION_FACTOR");
+  if (factor) {
+    long n = strtol(factor, nullptr, 10);
+    if (n != 0) {
+      sPropValue = n;
+      return sPropValue;
+    }
+  }
+  return sPropValue;
 }
 
 //
 // Strategy: Pipes
 //
 
 void
 Faulty::MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability)
 {
   if (!mFuzzPipes) {
     return;
   }
 
   if (aPipe > -1) {
-    FAULTY_LOG("collecting pipe %d to bucket of pipes (count: %ld)",
+    FAULTY_LOG("Collecting pipe %d to bucket of pipes (count: %ld)",
                aPipe, mFds.size());
     mFds.insert(aPipe);
   }
 
-  if (mFds.size() > 0 && GetChance(aProbability)) {
+  if (mFds.size() > 0 && FuzzingTraits::Sometimes(aProbability)) {
     std::set<int>::iterator it(mFds.begin());
-    std::advance(it, Random(mFds.size()));
-    FAULTY_LOG("trying to close collected pipe: %d", *it);
+    std::advance(it, FuzzingTraits::Random(mFds.size()));
+    FAULTY_LOG("Trying to close collected pipe: %d", *it);
     errno = 0;
     while ((close(*it) == -1 && (errno == EINTR))) {
       ;
     }
-    FAULTY_LOG("pipe status after attempt to close: %d", errno);
+    FAULTY_LOG("Pipe status after attempt to close: %d", errno);
     mFds.erase(it);
   }
 }
 
 //
 // Strategy: Pickle
 //
 
@@ -334,333 +385,535 @@ Faulty::MutateBool(bool* aValue)
 {
   *aValue = !(*aValue);
 }
 
 void
 Faulty::FuzzBool(bool* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       bool oldValue = *aValue;
       MutateBool(aValue);
-      FAULTY_LOG("pickle field {bool} of value: %d changed to: %d",
+      FAULTY_LOG("Message field |bool| of value: %d mutated to: %d",
                  (int)oldValue, (int)*aValue);
     }
   }
 }
 
 void
 Faulty::MutateChar(char* aValue)
 {
   FuzzIntegralType<char>(aValue, true);
 }
 
 void
 Faulty::FuzzChar(char* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       char oldValue = *aValue;
       MutateChar(aValue);
-      FAULTY_LOG("pickle field {char} of value: %c changed to: %c",
+      FAULTY_LOG("Message field |char| of value: %c mutated to: %c",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateUChar(unsigned char* aValue)
 {
   FuzzIntegralType<unsigned char>(aValue, true);
 }
 
 void
 Faulty::FuzzUChar(unsigned char* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       unsigned char oldValue = *aValue;
       MutateUChar(aValue);
-      FAULTY_LOG("pickle field {unsigned char} of value: %u changed to: %u",
+      FAULTY_LOG("Message field |unsigned char| of value: %u mutated to: %u",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateInt16(int16_t* aValue)
 {
   FuzzIntegralType<int16_t>(aValue, true);
 }
 
 void
 Faulty::FuzzInt16(int16_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       int16_t oldValue = *aValue;
       MutateInt16(aValue);
-      FAULTY_LOG("pickle field {Int16} of value: %d changed to: %d",
+      FAULTY_LOG("Message field |int16| of value: %d mutated to: %d",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateUInt16(uint16_t* aValue)
 {
   FuzzIntegralType<uint16_t>(aValue, true);
 }
 
 void
 Faulty::FuzzUInt16(uint16_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       uint16_t oldValue = *aValue;
       MutateUInt16(aValue);
-      FAULTY_LOG("pickle field {UInt16} of value: %d changed to: %d",
+      FAULTY_LOG("Message field |uint16| of value: %d mutated to: %d",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateInt(int* aValue)
 {
   FuzzIntegralType<int>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzInt(int* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       int oldValue = *aValue;
       MutateInt(aValue);
-      FAULTY_LOG("pickle field {int} of value: %d changed to: %d",
+      FAULTY_LOG("Message field |int| of value: %d mutated to: %d",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateUInt32(uint32_t* aValue)
 {
   FuzzIntegralType<uint32_t>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzUInt32(uint32_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       uint32_t oldValue = *aValue;
       MutateUInt32(aValue);
-      FAULTY_LOG("pickle field {UInt32} of value: %u changed to: %u",
+      FAULTY_LOG("Message field |uint32| of value: %u mutated to: %u",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateLong(long* aValue)
 {
   FuzzIntegralType<long>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzLong(long* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       long oldValue = *aValue;
       MutateLong(aValue);
-      FAULTY_LOG("pickle field {long} of value: %ld changed to: %ld",
+      FAULTY_LOG("Message field |long| of value: %ld mutated to: %ld",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateULong(unsigned long* aValue)
 {
   FuzzIntegralType<unsigned long>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzULong(unsigned long* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       unsigned long oldValue = *aValue;
       MutateULong(aValue);
-      FAULTY_LOG("pickle field {unsigned long} of value: %lu changed to: %lu",
+      FAULTY_LOG("Message field |unsigned long| of value: %lu mutated to: %lu",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateSize(size_t* aValue)
 {
   FuzzIntegralType<size_t>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzSize(size_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       size_t oldValue = *aValue;
       MutateSize(aValue);
-      FAULTY_LOG("pickle field {size_t} of value: %zu changed to: %zu",
+      FAULTY_LOG("Message field |size_t| of value: %zu mutated to: %zu",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateUInt64(uint64_t* aValue)
 {
   FuzzIntegralType<uint64_t>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzUInt64(uint64_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       uint64_t oldValue = *aValue;
       MutateUInt64(aValue);
-      FAULTY_LOG("pickle field {UInt64} of value: %" PRIu64 " changed to: %" PRIu64,
+      FAULTY_LOG("Message field |uint64| of value: %" PRIu64 " mutated to: %" PRIu64,
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateInt64(int64_t* aValue)
 {
   FuzzIntegralType<int64_t>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzInt64(int64_t* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       int64_t oldValue = *aValue;
       MutateInt64(aValue);
-      FAULTY_LOG("pickle field {UInt64} of value: %" PRIu64 " changed to: %" PRIu64,
+      FAULTY_LOG("Message field |int64| of value: %" PRIu64 " mutated to: %" PRIu64,
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateDouble(double* aValue)
 {
   FuzzFloatingPointType<double>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzDouble(double* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       double oldValue = *aValue;
       MutateDouble(aValue);
-      FAULTY_LOG("pickle field {double} of value: %f changed to: %f",
+      FAULTY_LOG("Message field |double| of value: %f mutated to: %f",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::MutateFloat(float* aValue)
 {
   FuzzFloatingPointType<float>(aValue, mUseLargeValues);
 }
 
 void
 Faulty::FuzzFloat(float* aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       float oldValue = *aValue;
       MutateFloat(aValue);
-      FAULTY_LOG("pickle field {float} of value: %f changed to: %f",
+      FAULTY_LOG("Message field |float| of value: %f mutated to: %f",
                  oldValue, *aValue);
     }
   }
 }
 
 void
 Faulty::FuzzString(std::string& aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       std::string oldValue = aValue;
       FuzzStringType<std::string>(aValue, "xoferiF", std::string());
-      FAULTY_LOG("pickle field {string} of value: %s changed to: %s",
+      FAULTY_LOG("Message field |string| of value: %s mutated to: %s",
                  oldValue.c_str(), aValue.c_str());
     }
   }
 }
 
 void
 Faulty::FuzzWString(std::wstring& aValue, unsigned int aProbability)
 {
   if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
+    if (mFuzzPickle && FuzzingTraits::Sometimes(aProbability)) {
       std::wstring oldValue = aValue;
-      FAULTY_LOG("pickle field {wstring}");
+      FAULTY_LOG("Message field |wstring|");
       FuzzStringType<std::wstring>(aValue, L"xoferiF", std::wstring());
     }
   }
 }
 
-void
-Faulty::FuzzString16(string16& aValue, unsigned int aProbability)
-{
-  if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
-      string16 oldValue = aValue;
-      FAULTY_LOG("pickle field {string16}");
-      FuzzStringType<string16>(aValue,
-        string16(ASCIIToUTF16(std::string("xoferiF"))),
-        string16(ASCIIToUTF16(std::string())));
+// static
+nsresult
+Faulty::CreateOutputDirectory(const char *aPathname) {
+  nsCOMPtr<nsIFile> path;
+  bool exists;
+  nsresult rv;
+
+  rv = NS_NewNativeLocalFile(nsDependentCString(aPathname),
+                             true,
+                             getter_AddRefs(path));
+
+  rv = path->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (!exists) {
+    rv = path->Create(nsIFile::DIRECTORY_TYPE, 0755);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
     }
   }
+
+  return NS_OK;
+}
+
+/* static */
+nsresult
+Faulty::ReadFile(const char* aPathname, nsTArray<nsCString> &aArray)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> file;
+
+  rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(aPathname),
+                       true,
+                       getter_AddRefs(file));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  bool exists = false;
+  rv = file->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv)) || !exists) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIFileInputStream> fileStream(
+    do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = fileStream->Init(file, -1, -1, 0);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(fileStream, &rv));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsAutoCString line;
+  bool more = true;
+  do {
+    rv = lineStream->ReadLine(line, &more);
+    if (line.IsEmpty()) {
+      continue;
+    }
+    if (line.CharAt(0) == '#') {
+      /* Ignore comments. */
+      continue;
+    }
+    aArray.AppendElement(line);
+  } while (more);
+
+  file.forget();
+
+  return NS_OK;
+}
+
+bool
+Faulty::IsMessageNameBlacklisted(const char *aMessageName) {
+  static bool sFileLoaded = false;
+  static nsTArray<nsCString> sMessageBlacklist;
+
+  if (!sFileLoaded && mBlacklistPath) {
+    if (ReadFile(mBlacklistPath, sMessageBlacklist) != NS_OK) {
+      return false;
+    }
+    sFileLoaded = true;
+  }
+
+  if (sMessageBlacklist.Length() == 0) {
+    return false;
+  }
+
+  return sMessageBlacklist.Contains(aMessageName);
+}
+
+// static
+std::vector<uint8_t>
+Faulty::GetDataFromIPCMessage(IPC::Message* aMsg)
+{
+  const Pickle::BufferList& buffers = aMsg->Buffers();
+  std::vector<uint8_t> data;
+  data.reserve(buffers.Size());
+
+  Pickle::BufferList::IterImpl i = buffers.Iter();
+  while (!i.Done()) {
+    size_t s = i.RemainingInSegment();
+    data.insert(data.end(), i.Data(), i.Data() + s);
+
+    i.Advance(buffers, s);
+  }
+
+  return data;
+}
+
+// static
+void
+Faulty::CopyFDs(IPC::Message* aDstMsg, IPC::Message* aSrcMsg) {
+    FileDescriptorSet* dstFdSet = aDstMsg->file_descriptor_set();
+    FileDescriptorSet* srcFdSet = aSrcMsg->file_descriptor_set();
+    for (size_t i = 0; i < srcFdSet->size(); i++) {
+        int fd = srcFdSet->GetDescriptorAt(i);
+        dstFdSet->Add(fd);
+    }
+}
+
+IPC::Message *
+Faulty::MutateIPCMessage(const char *aChannel, IPC::Message* aMsg, unsigned int aProbability) {
+  if (!mIsValidProcessType || !mFuzzMessages) {
+    return aMsg;
+  }
+
+  sMsgCounter += 1;
+  LogMessage(aChannel, aMsg);
+
+  /* Skip immediately if we shall not try to fuzz this message. */
+  if (!FuzzingTraits::Sometimes(aProbability)) {
+    return aMsg;
+  }
+
+  const bool isMessageListed = IsMessageNameBlacklisted(aMsg->name());
+
+  /* Check if this message is blacklisted and shall not get fuzzed. */
+  if (isMessageListed && !mUseAsWhitelist) {
+    FAULTY_LOG("BLACKLISTED: %s", aMsg->name());
+    return aMsg;
+  }
+
+  /* Check if the message is whitelisted. */
+  if (!isMessageListed && mUseAsWhitelist) {
+    /* Silently skip this message. */
+    return aMsg;
+  }
+
+  /* Retrieve BufferLists as data from original message. */
+  std::vector<uint8_t> data(GetDataFromIPCMessage(aMsg));
+
+  /* Check if there is enough data in the message to fuzz. */
+  uint32_t headerSize = aMsg->HeaderSizeFromData(nullptr, nullptr);
+  if (headerSize == data.size()) {
+    FAULTY_LOG("IGNORING: %s", aMsg->name());
+    return aMsg;
+  }
+
+  /* Mutate the message data. */
+  size_t maxMutations = FuzzingTraits::Frequency(data.size(), MutationFactor());
+  FAULTY_LOG("FUZZING (%zu bytes): %s", maxMutations, aMsg->name());
+  while (maxMutations--) {
+    /* Ignore the header data of the message. */
+    uint32_t pos = RandomIntegerRange<uint32_t>(headerSize, data.size() - 1);
+    switch (FuzzingTraits::Random(6)) {
+      case 0:
+        break;
+      case 1:
+        data.at(pos) = RandomIntegerRange<uint8_t>(0, 1);
+        break;
+      case 2:
+        data.at(pos) ^= (1 << RandomIntegerRange<uint8_t>(0, 8));
+        break;
+      default:
+        data.at(pos) = RandomIntegerRange<uint8_t>(255, 255);
+    }
+  }
+
+  /* Build new message. */
+  auto *mutatedMsg = new IPC::Message(reinterpret_cast<const char*>(data.data()), data.size());
+  CopyFDs(mutatedMsg, aMsg);
+
+  /* Dump original message for diff purposes. */
+  DumpMessage(aChannel, aMsg, nsPrintfCString(".%zu.o", sMsgCounter).get());
+  /* Dump mutated message for diff purposes. */
+  DumpMessage(aChannel, mutatedMsg, nsPrintfCString(".%zu.m", sMsgCounter).get());
+
+  delete aMsg;
+
+  return mutatedMsg;
 }
 
 void
-Faulty::FuzzBytes(void* aData, int aLength, unsigned int aProbability)
-{
-  if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
-      FAULTY_LOG("pickle field {bytes}");
-      // Too destructive. |WriteBytes| is used in many of the above data
-      // types as base function.
-      //FuzzData(static_cast<char*>(aData), aLength);
-    }
+Faulty::LogMessage(const char* aChannel, IPC::Message* aMsg) {
+  if (!mIsValidProcessType) {
+    return;
   }
+
+  std::string fileName = nsPrintfCString("message.%u.%zu",
+    getpid(), sMsgCounter).get();
+
+  FAULTY_LOG("Process: %u | Size: %10zu | %-20s | %s => %s",
+    XRE_GetProcessType(),
+    aMsg->Buffers().Size(),
+    fileName.c_str(),
+    aChannel,
+    aMsg->name());
 }
 
 void
-Faulty::FuzzData(std::string& aValue, int aLength, unsigned int aProbability)
+Faulty::DumpMessage(const char *aChannel, IPC::Message* aMsg, std::string aAppendix)
 {
-  if (mIsValidProcessType) {
-    if (mFuzzPickle && GetChance(aProbability)) {
-      FAULTY_LOG("pickle field {data}");
-      for (int i = 0; i < aLength; ++i) {
-        if (GetChance(aProbability)) {
-          FuzzIntegralType<char>(&aValue[i], true);
-        }
-      }
-    }
+  if (!mIsValidProcessType || !mMessagePath) {
+    return;
   }
+
+  std::vector<uint8_t> data(GetDataFromIPCMessage(aMsg));
+  std::string fileName;
+
+  if (!aAppendix.empty()) {
+    fileName = nsPrintfCString("%s/message.%u%s",
+      mMessagePath, getpid(), aAppendix.c_str()).get();
+  } else {
+    fileName = nsPrintfCString("%s/%s",
+      mMessagePath, fileName.c_str()).get();
+  }
+
+  std::fstream fp;
+  fp.open(fileName, std::fstream::out | std::fstream::binary);
+  fp.write(reinterpret_cast<const char*>(data.data()), data.size());
+  fp.close();
 }
 
 } // namespace ipc
 } // namespace mozilla
+
rename from ipc/glue/Faulty.h
rename to tools/fuzzing/faulty/Faulty.h
--- a/ipc/glue/Faulty.h
+++ b/tools/fuzzing/faulty/Faulty.h
@@ -4,24 +4,27 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_ipc_Faulty_h
 #define mozilla_ipc_Faulty_h
 
 #include <set>
 #include <string>
-#include "nsDebug.h"
+#include <vector>
 #include "base/string16.h"
 #include "base/singleton.h"
+#include "nsDebug.h"
+#include "nsTArray.h"
 
 #define FAULTY_DEFAULT_PROBABILITY 1000
+#define FAULTY_DEFAULT_MUTATION_FACTOR 10
 #define FAULTY_LOG(fmt, args...) \
   if (mozilla::ipc::Faulty::IsLoggingEnabled()) { \
-    printf_stderr("[Faulty] " fmt "\n", ## args); \
+    printf_stderr("[Faulty] (%10u) " fmt "\n", getpid(), ## args); \
   }
 
 namespace IPC {
   // Needed for blacklisting messages.
   class Message;
 }
 
 namespace mozilla {
@@ -31,58 +34,76 @@ class Faulty
 {
   public:
     // Used as a default argument for the Fuzz|datatype| methods.
     static const unsigned int sDefaultProbability;
 
     static unsigned int DefaultProbability(void);
     static bool Logging(void);
     static bool IsLoggingEnabled(void) { return sIsLoggingEnabled; }
+    static std::vector<uint8_t> GetDataFromIPCMessage(IPC::Message* aMsg);
+    static nsresult CreateOutputDirectory(const char *aPathname);
+    static nsresult ReadFile(const char* aPathname, nsTArray<nsCString> &aArray);
+    static void CopyFDs(IPC::Message* aDstMsg, IPC::Message* aSrcMsg);
 
+    // Fuzzing methods for Pickle.
     void FuzzBool(bool* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzChar(char* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUChar(unsigned char* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzInt16(int16_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUInt16(uint16_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzInt(int* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUInt32(uint32_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzLong(long* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzULong(unsigned long* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzInt64(int64_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzUInt64(uint64_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzSize(size_t* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzFloat(float* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzDouble(double* aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzString(std::string& aValue, unsigned int aProbability=sDefaultProbability);
     void FuzzWString(std::wstring& aValue, unsigned int aProbability=sDefaultProbability);
-    void FuzzString16(string16& aValue, unsigned int aProbability=sDefaultProbability);
-    void FuzzData(std::string& aData, int aLength, unsigned int aProbability=sDefaultProbability);
     void FuzzBytes(void* aData, int aLength, unsigned int aProbability=sDefaultProbability);
 
+    // Fuzzing methods for pipe fuzzing.
     void MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability=sDefaultProbability);
 
+    // Fuzzing methods for message blob fuzzing.
+    void DumpMessage(const char *aChannel, IPC::Message* aMsg, std::string aAppendix=nullptr);
+    bool IsMessageNameBlacklisted(const char* aMessageName);
+    IPC::Message* MutateIPCMessage(const char *aChannel, IPC::Message* aMsg,
+      unsigned int aProbability=sDefaultProbability);
+
+    void LogMessage(const char* aChannel, IPC::Message* aMsg);
+
   private:
     std::set<int> mFds;
 
+    const bool mFuzzMessages;
     const bool mFuzzPipes;
     const bool mFuzzPickle;
     const bool mUseLargeValues;
+    const bool mUseAsWhitelist;
     const bool mIsValidProcessType;
 
+    const char* mMessagePath;
+    const char* mBlacklistPath;
+
+    size_t sMsgCounter;
+
     static const bool sIsLoggingEnabled;
 
     Faulty();
     friend struct DefaultSingletonTraits<Faulty>;
     DISALLOW_EVIL_CONSTRUCTORS(Faulty);
 
     static bool IsValidProcessType(void);
+    static uint32_t MutationFactor();
 
-    unsigned int Random(unsigned int aMax);
-    bool GetChance(unsigned int aProbability);
-
+    // Fuzzing methods for Pickle
     void MutateBool(bool* aValue);
     void MutateChar(char* aValue);
     void MutateUChar(unsigned char* aValue);
     void MutateInt16(int16_t* aValue);
     void MutateUInt16(uint16_t* aValue);
     void MutateInt(int* aValue);
     void MutateUInt32(uint32_t* aValue);
     void MutateLong(long* aValue);
@@ -93,8 +114,9 @@ class Faulty
     void MutateFloat(float* aValue);
     void MutateDouble(double* aValue);
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif
+
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/faulty/moz.build
@@ -0,0 +1,18 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+  'Faulty.cpp'
+]
+
+EXPORTS.mozilla.ipc += [
+  'Faulty.h'
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
--- a/tools/fuzzing/moz.build
+++ b/tools/fuzzing/moz.build
@@ -7,16 +7,17 @@
 DIRS += [
   'interface',
   'registry',
 ]
 
 if not CONFIG['JS_STANDALONE']:
   DIRS += [
     'common',
+    'faulty',
     'messagemanager',
     'shmem',
   ]
 
 if CONFIG['LIBFUZZER']:
   DIRS += [
     'libfuzzer',
   ]