summaryrefslogtreecommitdiffstats
path: root/tools/fuzzing/ipc/IPCFuzzController.h
diff options
context:
space:
mode:
Diffstat (limited to 'tools/fuzzing/ipc/IPCFuzzController.h')
-rw-r--r--tools/fuzzing/ipc/IPCFuzzController.h216
1 files changed, 216 insertions, 0 deletions
diff --git a/tools/fuzzing/ipc/IPCFuzzController.h b/tools/fuzzing/ipc/IPCFuzzController.h
new file mode 100644
index 0000000000..756a68f38f
--- /dev/null
+++ b/tools/fuzzing/ipc/IPCFuzzController.h
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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/. */
+
+#ifndef mozilla_ipc_IPCFuzzController_h
+#define mozilla_ipc_IPCFuzzController_h
+
+#include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/HashTable.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/fuzzing/Nyx.h"
+#include "mozilla/ipc/MessageLink.h"
+
+#include "nsIRunnable.h"
+#include "nsThreadUtils.h"
+
+#include "chrome/common/ipc_message.h"
+#include "mojo/core/ports/name.h"
+#include "mojo/core/ports/event.h"
+
+#include "IPCMessageStart.h"
+
+#include <unordered_map>
+#include <unordered_set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#define MOZ_FUZZING_IPC_DROP_PEER(aReason) \
+ mozilla::fuzzing::IPCFuzzController::instance().OnDropPeer( \
+ aReason, __FILE__, __LINE__);
+
+#define MOZ_FUZZING_IPC_MT_CTOR() \
+ mozilla::fuzzing::IPCFuzzController::instance().OnMessageTaskStart();
+
+#define MOZ_FUZZING_IPC_MT_STOP() \
+ mozilla::fuzzing::IPCFuzzController::instance().OnMessageTaskStop();
+
+#define MOZ_FUZZING_IPC_PRE_FUZZ_MT_RUN() \
+ mozilla::fuzzing::IPCFuzzController::instance().OnPreFuzzMessageTaskRun();
+
+#define MOZ_FUZZING_IPC_PRE_FUZZ_MT_STOP() \
+ mozilla::fuzzing::IPCFuzzController::instance().OnPreFuzzMessageTaskStop();
+
+namespace mozilla {
+
+namespace ipc {
+// We can't include ProtocolUtils.h here
+class IProtocol;
+typedef IPCMessageStart ProtocolId;
+
+class NodeChannel;
+} // namespace ipc
+
+namespace fuzzing {
+
+class IPCFuzzController {
+ typedef std::pair<int32_t, uint64_t> SeqNoPair;
+
+ typedef std::pair<int32_t, mozilla::ipc::ProtocolId> ActorIdPair;
+
+ class IPCFuzzLoop final : public Runnable {
+ friend class IPCFuzzController;
+
+ public:
+ NS_DECL_NSIRUNNABLE
+
+ IPCFuzzLoop();
+
+ private:
+ ~IPCFuzzLoop() = default;
+ };
+
+ public:
+ static IPCFuzzController& instance();
+
+ void InitializeIPCTypes();
+ bool GetRandomIPCMessageType(mozilla::ipc::ProtocolId pId,
+ uint16_t typeOffset, uint32_t* type);
+
+ bool ObserveIPCMessage(mozilla::ipc::NodeChannel* channel,
+ IPC::Message& aMessage);
+ bool MakeTargetDecision(uint8_t portIndex, uint8_t portInstanceIndex,
+ uint8_t actorIndex, uint16_t typeOffset,
+ mojo::core::ports::PortName* name, int32_t* seqno,
+ uint64_t* fseqno, int32_t* actorId, uint32_t* type,
+ bool* is_cons, bool update = true);
+
+ void OnActorConnected(mozilla::ipc::IProtocol* protocol);
+ void OnActorDestroyed(mozilla::ipc::IProtocol* protocol);
+ void OnMessageError(mozilla::ipc::HasResultCodes::Result code,
+ const IPC::Message& aMsg);
+ void OnDropPeer(const char* reason, const char* file, int line);
+ void OnMessageTaskStart();
+ void OnMessageTaskStop();
+ void OnPreFuzzMessageTaskRun();
+ void OnPreFuzzMessageTaskStop();
+ void OnChildReady() { childReady = true; }
+ void OnRunnableDone() { runnableDone = true; }
+
+ uint32_t getPreFuzzMessageTaskCount() { return messageTaskCount; };
+ uint32_t getMessageStartCount() { return messageStartCount; };
+ uint32_t getMessageStopCount() { return messageStopCount; };
+
+ void StartFuzzing(mozilla::ipc::NodeChannel* channel, IPC::Message& aMessage);
+
+ void SynchronizeOnMessageExecution(uint32_t expected_messages);
+ void AddToplevelActor(mojo::core::ports::PortName name,
+ mozilla::ipc::ProtocolId protocolId);
+
+ // Used for the IPC_SingleMessage fuzzer
+ UniquePtr<IPC::Message> replaceIPCMessage(UniquePtr<IPC::Message> aMsg);
+ void syncAfterReplace();
+
+ private:
+ // This is a mapping from port name to a pair of last seen sequence numbers.
+ std::unordered_map<mojo::core::ports::PortName, SeqNoPair> portSeqNos;
+
+ // This is a mapping from port name to node name.
+ std::unordered_map<mojo::core::ports::PortName, mojo::core::ports::NodeName>
+ portNodeName;
+
+ // This is a mapping from port name to protocol name, purely for debugging.
+ std::unordered_map<mojo::core::ports::PortName, std::string>
+ portNameToProtocolName;
+
+ // This maps each ProtocolId (IPCMessageStart) to the number of valid
+ // messages for that particular type.
+ std::unordered_map<mozilla::ipc::ProtocolId, uint32_t> validMsgTypes;
+
+ // This is a mapping from port name to pairs of actor Id and ProtocolId.
+ std::unordered_map<mojo::core::ports::PortName, std::vector<ActorIdPair>>
+ actorIds;
+
+ // If set, `lastActorPortName` is valid and fuzzing is pinned to this port.
+ Atomic<bool> useLastPortName;
+
+ // Last port where a new actor appeared. Only valid with `useLastPortName`.
+ mojo::core::ports::PortName lastActorPortName;
+
+ // Counter to indicate how long fuzzing should stay pinned to the last
+ // actor that appeared on `lastActorPortName`.
+ Atomic<uint32_t> useLastActor;
+
+ // This is the deterministic ordering of toplevel actors for fuzzing.
+ // In this matrix, each row (toplevel index) corresponds to one toplevel
+ // actor *type* while each entry in that row is an instance of that type,
+ // since some actors usually have multiple instances alive while others
+ // don't. For the exact ordering, please check the constructor for this
+ // class.
+ std::vector<std::vector<mojo::core::ports::PortName>> portNames;
+ std::unordered_map<std::string, uint8_t> portNameToIndex;
+
+ // This is a set of all types that are constructors.
+ std::unordered_set<uint32_t> constructorTypes;
+
+ // This is the name of the target node. We select one Node based on a
+ // particular toplevel actor and then use this to pull in additional
+ // toplevel actors that are on the same node (i.e. belong to the same
+ // process pair).
+ mojo::core::ports::NodeName targetNodeName;
+ bool haveTargetNodeName = false;
+
+ // This indicates that we have started the fuzzing thread and fuzzing will
+ // begin shortly.
+ bool fuzzingStartPending = false;
+
+ // This is used as a signal from other threads that runnables we dispatched
+ // are completed. Right now we use this only when dispatching to the main
+ // thread to await the completion of all pending events.
+ Atomic<bool> runnableDone;
+
+ // This is used to signal that the other process we are talking to is ready
+ // to start fuzzing. In the case of Parent <-> Child, a special IPC message
+ // is used to signal this. We might not be able to start fuzzing immediately
+ // hough if not all toplevel actors have been created yet.
+ Atomic<bool> childReady;
+
+ // Current amount of pending message tasks.
+ Atomic<uint32_t> messageStartCount;
+ Atomic<uint32_t> messageStopCount;
+
+ Atomic<uint32_t> messageTaskCount;
+
+ Vector<char, 256, InfallibleAllocPolicy> sampleHeader;
+
+ mozilla::ipc::NodeChannel* nodeChannel = nullptr;
+
+ // This class is used both on the I/O and background threads as well as
+ // its own fuzzing thread. Those methods that alter non-threadsafe data
+ // structures need to aquire this mutex first.
+ Mutex mMutex; // MOZ_UNANNOTATED;
+
+ // Can be used to specify a non-standard trigger message, e.h. to target
+ // a specific actor.
+ uint32_t mIPCTriggerMsg;
+
+ // Used to dump IPC messages in single message mode
+ Maybe<uint32_t> mIPCDumpMsg;
+ Maybe<uint32_t> mIPCDumpAllMsgsSize;
+ uint32_t mIPCDumpCount = 0;
+
+ // Used to select a particular packet instance in single message mode
+ uint32_t mIPCTriggerSingleMsgWait = 0;
+
+ IPCFuzzController();
+ NYX_DISALLOW_COPY_AND_ASSIGN(IPCFuzzController);
+};
+
+} // namespace fuzzing
+} // namespace mozilla
+
+#endif