Skip to content

Commit

Permalink
Bug 1896674 - Add allow/deny lists to IPCFuzzController. r=truber
Browse files Browse the repository at this point in the history
  • Loading branch information
choller committed May 22, 2024
1 parent beb16d8 commit 14c5abb
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 1 deletion.
128 changes: 127 additions & 1 deletion tools/fuzzing/ipc/IPCFuzzController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<std::string> 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<std::string> 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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand All @@ -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",
Expand Down
11 changes: 11 additions & 0 deletions tools/fuzzing/ipc/IPCFuzzController.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include <unordered_map>
#include <unordered_set>
#include <set>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -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<IPC::Message> replaceIPCMessage(UniquePtr<IPC::Message> aMsg);
void syncAfterReplace();
Expand Down Expand Up @@ -156,6 +160,13 @@ class IPCFuzzController {
// If this is non-zero, we want a specific actor ID instead of the last.
Atomic<int32_t> 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<uint32_t> actorAllowedMessages;

// Don't ever send messages contained in this set.
std::set<uint32_t> 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,
Expand Down

0 comments on commit 14c5abb

Please sign in to comment.