From 14c5abbd778caa22b8b85bd78340411de8bbb2fc Mon Sep 17 00:00:00 2001 From: "Christian Holler (:decoder)" Date: Wed, 22 May 2024 08:03:32 +0000 Subject: [PATCH] Bug 1896674 - Add allow/deny lists to IPCFuzzController. r=truber Differential Revision: https://phabricator.services.mozilla.com/D210439 --- tools/fuzzing/ipc/IPCFuzzController.cpp | 128 +++++++++++++++++++++++- tools/fuzzing/ipc/IPCFuzzController.h | 11 ++ 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/tools/fuzzing/ipc/IPCFuzzController.cpp b/tools/fuzzing/ipc/IPCFuzzController.cpp index ba52ec4095d2..b8469899f6e0 100644 --- a/tools/fuzzing/ipc/IPCFuzzController.cpp +++ b/tools/fuzzing/ipc/IPCFuzzController.cpp @@ -138,11 +138,21 @@ void IPCFuzzController::InitializeIPCTypes() { validMsgTypes[(ProtocolId)start] = msgCount; } } + + // Resolve potentially disallowed messages now that we have initialized IPC + // types. + InitDisallowedIPCTypes(); } bool IPCFuzzController::GetRandomIPCMessageType(ProtocolId pId, uint16_t typeOffset, uint32_t* type) { + if (actorAllowedMessages.size() > 0) { + // We are fixed to a single actor with a particular message set allowed. + *type = actorAllowedMessages[typeOffset % actorAllowedMessages.size()]; + return true; + } + auto pIdEntry = validMsgTypes.find(pId); if (pIdEntry == validMsgTypes.end()) { return false; @@ -155,9 +165,116 @@ bool IPCFuzzController::GetRandomIPCMessageType(ProtocolId pId, *type = *type - 1; } + // Check if we are allowed to send this message type. + if (actorDisallowedMessages.find(*type) != actorDisallowedMessages.end()) { + return false; + } + return true; } +void IPCFuzzController::InitDisallowedIPCTypes() { + const char* targetMsgName = getenv("MOZ_FUZZ_IPC_MSGFILTER_DISALLOW"); + if (!targetMsgName) { + // Nothing to do. + return; + } + + std::vector targetMsgNames; + std::istringstream targetMsgNameStream(targetMsgName); + for (std::string msg; getline(targetMsgNameStream, msg, ';');) { + targetMsgNames.push_back(msg); + } + + for (auto pIdEntry : validMsgTypes) { + for (uint16_t typeOffset = 0; typeOffset < pIdEntry.second; ++typeOffset) { + uint32_t type = ((uint32_t)pIdEntry.first << 16) + 1 + typeOffset; + const char* msgName = IPC::StringFromIPCMessageType(type); + if (strstr(msgName, "::Reply_")) { + continue; + } + + for (std::string msg : targetMsgNames) { + if (strstr(msgName, msg.c_str())) { + actorDisallowedMessages.insert(type); + break; + } + } + } + } +} + +void IPCFuzzController::InitAllowedIPCTypes() { + const char* targetMsgName = getenv("MOZ_FUZZ_IPC_MSGFILTER_ALLOW"); + if (!targetMsgName) { + // Nothing to do. + return; + } + + std::vector targetMsgNames; + std::istringstream targetMsgNameStream(targetMsgName); + for (std::string msg; getline(targetMsgNameStream, msg, ';');) { + targetMsgNames.push_back(msg); + } + + if (!maybeLastActorId) { + // We only want to call this if we are actually pinning to an actor. + // This also means that calling this is only valid with a PROTOID_FILTER + // set. + MOZ_FUZZING_NYX_ABORT("InitAllowedIPCTypes called without actor pinned?!"); + } + + auto result = actorIds.find(lastActorPortName); + if (result == actorIds.end()) { + MOZ_FUZZING_NYX_ABORT("ERROR: Couldn't find port in actors map?!\n"); + } + auto actors = result->second; + + bool found = false; + size_t actorIndex; + for (actorIndex = 0; actorIndex < actors.size(); ++actorIndex) { + if (actors[actorIndex].first == maybeLastActorId || + (maybeLastActorId == MSG_ROUTING_CONTROL && + !actors[actorIndex].first)) { + found = true; + break; + } + } + + if (!found) { + MOZ_FUZZING_NYX_ABORT( + "ERROR: Pinned to actor that's not in actors map!?\n"); + } + + ActorIdPair ids = actors[actorIndex]; + + ProtocolId pId = ids.second; + + auto pIdEntry = validMsgTypes.find(pId); + if (pIdEntry == validMsgTypes.end()) { + MOZ_FUZZING_NYX_ABORT("ERROR: Pinned actor has no valid message types!?\n"); + } + + for (uint16_t typeOffset = 0; typeOffset < pIdEntry->second; ++typeOffset) { + uint32_t type = ((uint32_t)pIdEntry->first << 16) + 1 + typeOffset; + const char* msgName = IPC::StringFromIPCMessageType(type); + if (strstr(msgName, "::Reply_")) { + continue; + } + + for (std::string msg : targetMsgNames) { + if (strstr(msgName, msg.c_str())) { + actorAllowedMessages.push_back(type); + break; + } + } + } + + if (!actorAllowedMessages.size()) { + MOZ_FUZZING_NYX_ABORT("ERROR: Empty actorAllowedMessages!?\n"); + } +} + static bool IsManagedByTargetActor(IProtocol* protocol, std::string& protoIdFilter) { while (protocol) { @@ -390,6 +507,8 @@ bool IPCFuzzController::ObserveIPCMessage(mozilla::ipc::NodeChannel* channel, MOZ_FUZZING_NYX_PRINTF("DEBUG: Pinned to port %lu %lu forever.\n", lastActorPortName.v1, lastActorPortName.v2); } + + InitAllowedIPCTypes(); } // TODO: This is specific to PContent fuzzing. If we later want to fuzz @@ -716,7 +835,7 @@ bool IPCFuzzController::MakeTargetDecision( *actorId = MSG_ROUTING_CONTROL; } - if (!isPreserveHeader) { + if (!isPreserveHeader || actorAllowedMessages.size() > 0) { // If msgType is already set, then we are in preserveHeaderMode if (!this->GetRandomIPCMessageType(ids.second, typeOffset, type)) { MOZ_FUZZING_NYX_PRINT("ERROR: GetRandomIPCMessageType failed?!\n"); @@ -729,6 +848,13 @@ bool IPCFuzzController::MakeTargetDecision( } } + if (isPreserveHeader && + actorDisallowedMessages.find(*type) != actorDisallowedMessages.end()) { + // If we have messages that aren't allowed to be sent, we need to + // confirm that the type set in the header is still allowed. + return false; + } + MOZ_FUZZING_NYX_PRINTF( "DEBUG: MakeTargetDecision: Top-Level Protocol: %s Protocol: %s msgType: " "%s (%u), Actor Instance %u of %zu, actor ID: %d, PreservedHeader: %d\n", diff --git a/tools/fuzzing/ipc/IPCFuzzController.h b/tools/fuzzing/ipc/IPCFuzzController.h index 5c27443381eb..55f4a205dc63 100644 --- a/tools/fuzzing/ipc/IPCFuzzController.h +++ b/tools/fuzzing/ipc/IPCFuzzController.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -111,6 +112,9 @@ class IPCFuzzController { void AddToplevelActor(mojo::core::ports::PortName name, mozilla::ipc::ProtocolId protocolId); + void InitAllowedIPCTypes(); + void InitDisallowedIPCTypes(); + // Used for the IPC_SingleMessage fuzzer UniquePtr replaceIPCMessage(UniquePtr aMsg); void syncAfterReplace(); @@ -156,6 +160,13 @@ class IPCFuzzController { // If this is non-zero, we want a specific actor ID instead of the last. Atomic maybeLastActorId; + // If this is non-empty and in certain configurations, we only use a fixed + // set of messages, rather than sending any message type for that actor. + std::vector actorAllowedMessages; + + // Don't ever send messages contained in this set. + std::set actorDisallowedMessages; + // 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,