/* -*- 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 #include #include #include #include #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 SeqNoPair; typedef std::pair 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 replaceIPCMessage(UniquePtr aMsg); void syncAfterReplace(); private: // This is a mapping from port name to a pair of last seen sequence numbers. std::unordered_map portSeqNos; // This is a mapping from port name to node name. std::unordered_map portNodeName; // This is a mapping from port name to protocol name, purely for debugging. std::unordered_map portNameToProtocolName; // This maps each ProtocolId (IPCMessageStart) to the number of valid // messages for that particular type. std::unordered_map validMsgTypes; // This is a mapping from port name to pairs of actor Id and ProtocolId. std::unordered_map> actorIds; // If set, `lastActorPortName` is valid and fuzzing is pinned to this port. Atomic 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 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> portNames; std::unordered_map portNameToIndex; // This is a set of all types that are constructors. std::unordered_set 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 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 childReady; // Current amount of pending message tasks. Atomic messageStartCount; Atomic messageStopCount; Atomic messageTaskCount; Vector 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 mIPCDumpMsg; Maybe 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