summaryrefslogtreecommitdiffstats
path: root/tools/fuzzing
diff options
context:
space:
mode:
Diffstat (limited to 'tools/fuzzing')
-rw-r--r--tools/fuzzing/interface/FuzzingInterface.cpp39
-rw-r--r--tools/fuzzing/interface/FuzzingInterface.h48
-rw-r--r--tools/fuzzing/interface/FuzzingInterfaceStream.cpp54
-rw-r--r--tools/fuzzing/interface/FuzzingInterfaceStream.h41
-rw-r--r--tools/fuzzing/interface/harness/FuzzerTestHarness.h1
-rw-r--r--tools/fuzzing/interface/moz.build4
-rw-r--r--tools/fuzzing/ipc/IPCFuzzController.cpp240
-rw-r--r--tools/fuzzing/ipc/IPCFuzzController.h13
-rw-r--r--tools/fuzzing/smoke/smoke.py2
9 files changed, 255 insertions, 187 deletions
diff --git a/tools/fuzzing/interface/FuzzingInterface.cpp b/tools/fuzzing/interface/FuzzingInterface.cpp
index f06ca68656..ba932c4b2a 100644
--- a/tools/fuzzing/interface/FuzzingInterface.cpp
+++ b/tools/fuzzing/interface/FuzzingInterface.cpp
@@ -28,3 +28,42 @@ LazyLogModule gFuzzingLog("nsFuzzing");
#endif
} // namespace mozilla
+
+#ifdef AFLFUZZ
+__AFL_FUZZ_INIT();
+
+int afl_interface_raw(FuzzingTestFuncRaw testFunc) {
+ __AFL_INIT();
+ char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE");
+ uint8_t* buf = NULL;
+
+ if (testFilePtr) {
+ std::string testFile(testFilePtr);
+ while (__AFL_LOOP(1000)) {
+ std::ifstream is;
+ is.open(testFile, std::ios::binary);
+ is.seekg(0, std::ios::end);
+ size_t len = is.tellg();
+ is.seekg(0, std::ios::beg);
+ MOZ_RELEASE_ASSERT(len >= 0);
+ if (!len) {
+ is.close();
+ continue;
+ }
+ buf = reinterpret_cast<uint8_t*>(realloc(buf, len));
+ MOZ_RELEASE_ASSERT(buf);
+ is.read(reinterpret_cast<char*>(buf), len);
+ is.close();
+ testFunc(buf, len);
+ }
+ } else {
+ buf = __AFL_FUZZ_TESTCASE_BUF;
+ while (__AFL_LOOP(1000)) {
+ size_t len = __AFL_FUZZ_TESTCASE_LEN;
+ testFunc(buf, len);
+ }
+ }
+
+ return 0;
+}
+#endif // AFLFUZZ
diff --git a/tools/fuzzing/interface/FuzzingInterface.h b/tools/fuzzing/interface/FuzzingInterface.h
index 792f0809ec..31a4b50867 100644
--- a/tools/fuzzing/interface/FuzzingInterface.h
+++ b/tools/fuzzing/interface/FuzzingInterface.h
@@ -37,55 +37,17 @@ extern LazyLogModule gFuzzingLog;
MOZ_LOG(mozilla::gFuzzingLog, mozilla::LogLevel::Verbose, args)
#endif // JS_STANDALONE
+} // namespace mozilla
+
typedef int (*FuzzingTestFuncRaw)(const uint8_t*, size_t);
#ifdef AFLFUZZ
-static int afl_interface_raw(const char* testFile,
- FuzzingTestFuncRaw testFunc) {
- char* buf = NULL;
-
- while (__AFL_LOOP(1000)) {
- std::ifstream is;
- is.open(testFile, std::ios::binary);
- is.seekg(0, std::ios::end);
- int len = is.tellg();
- is.seekg(0, std::ios::beg);
- MOZ_RELEASE_ASSERT(len >= 0);
- if (!len) {
- is.close();
- continue;
- }
- buf = (char*)realloc(buf, len);
- MOZ_RELEASE_ASSERT(buf);
- is.read(buf, len);
- is.close();
- testFunc((uint8_t*)buf, (size_t)len);
- }
-
- free(buf);
-
- return 0;
-}
-
-# define MOZ_AFL_INTERFACE_COMMON() \
- char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE"); \
- if (!testFilePtr) { \
- fprintf(stderr, \
- "Must specify testfile in MOZ_FUZZ_TESTFILE environment " \
- "variable.\n"); \
- return 1; \
- } \
- /* Make a copy of testFilePtr so the testing function can safely call \
- * getenv \
- */ \
- std::string testFile(testFilePtr);
+int afl_interface_raw(FuzzingTestFuncRaw testFunc);
# define MOZ_AFL_INTERFACE_RAW(initFunc, testFunc, moduleName) \
static int afl_fuzz_##moduleName(const uint8_t* data, size_t size) { \
- MOZ_RELEASE_ASSERT(data == NULL && size == 0); \
- MOZ_AFL_INTERFACE_COMMON(); \
- return ::mozilla::afl_interface_raw(testFile.c_str(), testFunc); \
+ return afl_interface_raw(testFunc); \
} \
static void __attribute__((constructor)) AFLRegister##moduleName() { \
::mozilla::FuzzerRegistry::getInstance().registerModule( \
@@ -110,6 +72,4 @@ static int afl_interface_raw(const char* testFile,
MOZ_LIBFUZZER_INTERFACE_RAW(initFunc, testFunc, moduleName); \
MOZ_AFL_INTERFACE_RAW(initFunc, testFunc, moduleName);
-} // namespace mozilla
-
#endif // FuzzingInterface_h__
diff --git a/tools/fuzzing/interface/FuzzingInterfaceStream.cpp b/tools/fuzzing/interface/FuzzingInterfaceStream.cpp
deleted file mode 100644
index f2c5c891e9..0000000000
--- a/tools/fuzzing/interface/FuzzingInterfaceStream.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-/*
- * Interface implementation for the unified fuzzing interface
- */
-
-#include "nsIFile.h"
-#include "nsIPrefService.h"
-#include "nsIProperties.h"
-
-#include "FuzzingInterfaceStream.h"
-
-#include "mozilla/Assertions.h"
-
-#ifndef JS_STANDALONE
-# include "nsNetUtil.h"
-#endif
-
-namespace mozilla {
-
-#ifdef AFLFUZZ
-
-void afl_interface_stream(const char* testFile,
- FuzzingTestFuncStream testFunc) {
- nsresult rv;
- nsCOMPtr<nsIProperties> dirService =
- do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
- MOZ_RELEASE_ASSERT(dirService != nullptr);
- nsCOMPtr<nsIFile> file;
- rv = dirService->Get(NS_OS_CURRENT_WORKING_DIR, NS_GET_IID(nsIFile),
- getter_AddRefs(file));
- MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
- file->AppendNative(nsDependentCString(testFile));
- while (__AFL_LOOP(1000)) {
- nsCOMPtr<nsIInputStream> inputStream;
- rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file);
- MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
- if (!NS_InputStreamIsBuffered(inputStream)) {
- nsCOMPtr<nsIInputStream> bufStream;
- rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream),
- inputStream.forget(), 1024);
- MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
- inputStream = bufStream;
- }
- testFunc(inputStream.forget());
- }
-}
-
-#endif
-
-} // namespace mozilla
diff --git a/tools/fuzzing/interface/FuzzingInterfaceStream.h b/tools/fuzzing/interface/FuzzingInterfaceStream.h
index 1542020794..44807d9ebd 100644
--- a/tools/fuzzing/interface/FuzzingInterfaceStream.h
+++ b/tools/fuzzing/interface/FuzzingInterfaceStream.h
@@ -28,32 +28,25 @@
#include "FuzzingInterface.h"
-namespace mozilla {
-
typedef int (*FuzzingTestFuncStream)(nsCOMPtr<nsIInputStream>);
#ifdef AFLFUZZ
-void afl_interface_stream(const char* testFile, FuzzingTestFuncStream testFunc);
-
-# define MOZ_AFL_INTERFACE_COMMON(initFunc) \
- if (initFunc) initFunc(NULL, NULL); \
- char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE"); \
- if (!testFilePtr) { \
- fprintf(stderr, \
- "Must specify testfile in MOZ_FUZZ_TESTFILE environment " \
- "variable.\n"); \
- return; \
- } \
- /* Make a copy of testFilePtr so the testing function can safely call \
- * getenv \
- */ \
- std::string testFile(testFilePtr);
-
-# define MOZ_AFL_INTERFACE_STREAM(initFunc, testFunc, moduleName) \
- TEST(AFL, moduleName) \
- { \
- MOZ_AFL_INTERFACE_COMMON(initFunc); \
- ::mozilla::afl_interface_stream(testFile.c_str(), testFunc); \
+# define MOZ_AFL_INTERFACE_STREAM(initFunc, testFunc, moduleName) \
+ static int afl_fuzz_inner_##moduleName(const uint8_t* data, size_t size) { \
+ if (size > INT32_MAX) return 0; \
+ nsCOMPtr<nsIInputStream> stream; \
+ nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), \
+ Span((const char*)data, size), \
+ NS_ASSIGNMENT_DEPEND); \
+ MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); \
+ return testFunc(stream.forget()); \
+ } \
+ static int afl_fuzz_##moduleName(const uint8_t* data, size_t size) { \
+ return afl_interface_raw(afl_fuzz_inner_##moduleName); \
+ } \
+ static void __attribute__((constructor)) AFLRegister##moduleName() { \
+ ::mozilla::FuzzerRegistry::getInstance().registerModule( \
+ #moduleName, initFunc, afl_fuzz_##moduleName); \
}
#else
# define MOZ_AFL_INTERFACE_STREAM(initFunc, testFunc, moduleName) /* Nothing \
@@ -85,6 +78,4 @@ void afl_interface_stream(const char* testFile, FuzzingTestFuncStream testFunc);
MOZ_LIBFUZZER_INTERFACE_STREAM(initFunc, testFunc, moduleName); \
MOZ_AFL_INTERFACE_STREAM(initFunc, testFunc, moduleName);
-} // namespace mozilla
-
#endif // FuzzingInterfaceStream_h__
diff --git a/tools/fuzzing/interface/harness/FuzzerTestHarness.h b/tools/fuzzing/interface/harness/FuzzerTestHarness.h
index d7bb1064cf..6104be5438 100644
--- a/tools/fuzzing/interface/harness/FuzzerTestHarness.h
+++ b/tools/fuzzing/interface/harness/FuzzerTestHarness.h
@@ -14,6 +14,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
+#include "mozilla/IntegerPrintfMacros.h"
#include "prenv.h"
#include "nsComponentManagerUtils.h"
diff --git a/tools/fuzzing/interface/moz.build b/tools/fuzzing/interface/moz.build
index 8a51007174..fbfb59d924 100644
--- a/tools/fuzzing/interface/moz.build
+++ b/tools/fuzzing/interface/moz.build
@@ -21,10 +21,6 @@ else:
"FuzzingInterfaceStream.h",
]
- SOURCES += [
- "FuzzingInterfaceStream.cpp",
- ]
-
DIRS += [
"harness",
]
diff --git a/tools/fuzzing/ipc/IPCFuzzController.cpp b/tools/fuzzing/ipc/IPCFuzzController.cpp
index 7eee9102c0..ba52ec4095 100644
--- a/tools/fuzzing/ipc/IPCFuzzController.cpp
+++ b/tools/fuzzing/ipc/IPCFuzzController.cpp
@@ -52,6 +52,8 @@ const uint32_t ipcDefaultTriggerMsg = dom::PContent::Msg_SignalFuzzingReady__ID;
IPCFuzzController::IPCFuzzController()
: useLastPortName(false),
+ useLastPortNameAlways(false),
+ protoFilterTargetExcludeToplevel(false),
useLastActor(0),
mMutex("IPCFuzzController"),
mIPCTriggerMsg(ipcDefaultTriggerMsg) {
@@ -156,6 +158,18 @@ bool IPCFuzzController::GetRandomIPCMessageType(ProtocolId pId,
return true;
}
+static bool IsManagedByTargetActor(IProtocol* protocol,
+ std::string& protoIdFilter) {
+ while (protocol) {
+ if (!strcmp(protocol->GetProtocolName(), protoIdFilter.c_str())) {
+ return true;
+ }
+
+ protocol = protocol->Manager();
+ }
+ return false;
+}
+
void IPCFuzzController::OnActorConnected(IProtocol* protocol) {
if (!XRE_IsParentProcess()) {
return;
@@ -171,7 +185,8 @@ void IPCFuzzController::OnActorConnected(IProtocol* protocol) {
"DEBUG: IPCFuzzController::OnActorConnected() Mutex locked\n");
static bool protoIdFilterInitialized = false;
- static bool allowNewActors = false;
+ static bool allowSubActors =
+ !!getenv("MOZ_FUZZ_PROTOID_FILTER_ALLOW_SUBACTORS");
static std::string protoIdFilter;
if (!protoIdFilterInitialized) {
const char* protoIdFilterStr = getenv("MOZ_FUZZ_PROTOID_FILTER");
@@ -181,42 +196,67 @@ void IPCFuzzController::OnActorConnected(IProtocol* protocol) {
protoIdFilterInitialized = true;
}
-#ifdef FUZZ_DEBUG
- MOZ_FUZZING_NYX_PRINTF("INFO: [OnActorConnected] ActorID %d Protocol: %s\n",
- protocol->Id(), protocol->GetProtocolName());
-#endif
-
MessageChannel* channel = protocol->ToplevelProtocol()->GetIPCChannel();
Maybe<PortName> portName = channel->GetPortName();
+
+ if (!portName) {
+ MOZ_FUZZING_NYX_PRINTF("INFO: [OnActorConnected] ActorID %d Protocol: %s\n",
+ protocol->Id(), protocol->GetProtocolName());
+ }
+
if (portName) {
- if (!protoIdFilter.empty() &&
- (!Nyx::instance().started() || !allowNewActors) &&
- strcmp(protocol->GetProtocolName(), protoIdFilter.c_str()) &&
- !actorIds[*portName].empty()) {
- MOZ_FUZZING_NYX_PRINTF(
- "INFO: [OnActorConnected] ActorID %d Protocol: %s ignored due to "
- "filter.\n",
- protocol->Id(), protocol->GetProtocolName());
- return;
- } else if (!protoIdFilter.empty() &&
- !strcmp(protocol->GetProtocolName(), protoIdFilter.c_str())) {
- MOZ_FUZZING_NYX_PRINTF(
- "INFO: [OnActorConnected] ActorID %d Protocol: %s matches target.\n",
- protocol->Id(), protocol->GetProtocolName());
- } else if (!protoIdFilter.empty() && actorIds[*portName].empty()) {
+ if (!protoIdFilter.empty()) {
+ if (!strcmp(protocol->GetProtocolName(), protoIdFilter.c_str())) {
+ MOZ_FUZZING_NYX_PRINTF(
+ "INFO: [OnActorConnected] ActorID %d Protocol: %s matches "
+ "target.\n",
+ protocol->Id(), protocol->GetProtocolName());
+
+ // If our matching protocol is not a toplevel actor, then we need to
+ // exclude the toplevel protocol later in `MakeTargetDecision` because
+ // the actor will always be added to the map.
+ protoFilterTargetExcludeToplevel = protocol->Manager() != nullptr;
+ } else if (actorIds[*portName].empty()) {
+ MOZ_FUZZING_NYX_PRINTF(
+ "INFO: [OnActorConnected] ActorID %d Protocol: %s is toplevel "
+ "actor.\n",
+ protocol->Id(), protocol->GetProtocolName());
+ } else if (allowSubActors &&
+ IsManagedByTargetActor(protocol, protoIdFilter)) {
+ MOZ_FUZZING_NYX_PRINTF(
+ "INFO: [OnActorConnected] ActorID %d Protocol: %s is managed by "
+ "target actor.\n",
+ protocol->Id(), protocol->GetProtocolName());
+ } else {
+ // Not a toplevel actor, not matching the filter and also either not a
+ // sub actor of our target or we are focusing only on the target. Ignore
+ // this actor.
+ if (!!getenv("MOZ_FUZZ_DEBUG")) {
+ MOZ_FUZZING_NYX_PRINTF(
+ "INFO: [OnActorConnected] ActorID %d Protocol: %s ignored due to "
+ "filter.\n",
+ protocol->Id(), protocol->GetProtocolName());
+ }
+ return;
+ }
+ }
+
+ if (!!getenv("MOZ_FUZZ_DEBUG")) {
MOZ_FUZZING_NYX_PRINTF(
- "INFO: [OnActorConnected] ActorID %d Protocol: %s is toplevel "
- "actor.\n",
- protocol->Id(), protocol->GetProtocolName());
+ "INFO: [OnActorConnected] ActorID %d Protocol: %s Port: %lu %lu\n",
+ protocol->Id(), protocol->GetProtocolName(), portName->v1,
+ portName->v2);
}
actorIds[*portName].emplace_back(protocol->Id(), protocol->GetProtocolId());
- if (Nyx::instance().started() && protoIdFilter.empty()) {
- // Fix the port we will be using for at least the next 5 messages
- useLastPortName = true;
- lastActorPortName = *portName;
+ if (Nyx::instance().started()) {
+ if (!useLastPortNameAlways) {
+ // Fix the port we will be using for at least the next 5 messages
+ useLastPortName = true;
+ lastActorPortName = *portName;
+ }
// Use this actor for the next 5 messages
useLastActor = 5;
@@ -247,6 +287,16 @@ void IPCFuzzController::OnActorDestroyed(IProtocol* protocol) {
MOZ_FUZZING_NYX_DEBUG(
"DEBUG: IPCFuzzController::OnActorDestroyed() Mutex locked\n");
+ if (maybeLastActorId &&
+ (maybeLastActorId == protocol->Id() ||
+ (maybeLastActorId == MSG_ROUTING_CONTROL && !protocol->Id())) &&
+ lastActorPortName == *portName) {
+ MOZ_FUZZING_NYX_DEBUG("INFO: Actor pinning released.\n");
+ // We destroyed the actor we were focusing on, unpin.
+ maybeLastActorId = 0;
+ useLastActor = 0;
+ }
+
for (auto iter = actorIds[*portName].begin();
iter != actorIds[*portName].end();) {
if (iter->first == protocol->Id() &&
@@ -293,13 +343,14 @@ bool IPCFuzzController::ObserveIPCMessage(mozilla::ipc::NodeChannel* channel,
if (!channel->mBlockSendRecv) {
MOZ_FUZZING_NYX_PRINTF(
"INFO: [NodeChannel::OnMessageReceived] Blocking further "
- "communication on Port %lu %lu (seen fuzz msg)\n",
+ "communication on node %lu %lu (seen fuzz msg)\n",
channel->GetName().v1, channel->GetName().v2);
channel->mBlockSendRecv = true;
}
return true;
} else if (aMessage.type() == mIPCTriggerMsg && !Nyx::instance().started()) {
- MOZ_FUZZING_NYX_PRINT("DEBUG: Ready message detected.\n");
+ MOZ_FUZZING_NYX_PRINTF("DEBUG: Ready message detected on actor %d.\n",
+ aMessage.routing_id());
if (!haveTargetNodeName && !!getenv("MOZ_FUZZ_PROTOID_FILTER")) {
// With a protocol filter set, we want to pin to the actor that
@@ -322,8 +373,23 @@ bool IPCFuzzController::ObserveIPCMessage(mozilla::ipc::NodeChannel* channel,
}
lastActorPortName = event->port_name();
- useLastPortName = true;
- useLastActor = 1024;
+ useLastPortNameAlways = true;
+
+ if (!getenv("MOZ_FUZZ_PROTOID_FILTER_ALLOW_SUBACTORS")) {
+ // In this mode, we really want to focus on a single actor.
+ useLastActor = 1024;
+ maybeLastActorId = aMessage.routing_id();
+ MOZ_FUZZING_NYX_PRINTF("DEBUG: Pinned to actor %d forever.\n",
+ aMessage.routing_id());
+ } else {
+ // In this mode, we want to focus on a particular actor and all of its
+ // sub actors. This means we have to pin the port at least. Undesired
+ // other actors are filtered out already in OnActorConnected *except*
+ // for the toplevel actor belonging to this port. This exception is
+ // handled separately in MakeTargetDecision.
+ MOZ_FUZZING_NYX_PRINTF("DEBUG: Pinned to port %lu %lu forever.\n",
+ lastActorPortName.v1, lastActorPortName.v2);
+ }
}
// TODO: This is specific to PContent fuzzing. If we later want to fuzz
@@ -353,7 +419,7 @@ bool IPCFuzzController::ObserveIPCMessage(mozilla::ipc::NodeChannel* channel,
if (!channel->mBlockSendRecv) {
MOZ_FUZZING_NYX_PRINTF(
"INFO: [NodeChannel::OnMessageReceived] Blocking further "
- "communication on Port %lu %lu (fuzzing started)\n",
+ "communication on node %lu %lu (fuzzing started)\n",
channel->GetName().v1, channel->GetName().v2);
channel->mBlockSendRecv = true;
}
@@ -428,13 +494,14 @@ bool IPCFuzzController::ObserveIPCMessage(mozilla::ipc::NodeChannel* channel,
if (!channel->mBlockSendRecv) {
MOZ_FUZZING_NYX_PRINTF(
"INFO: [NodeChannel::OnMessageReceived] Blocking further "
- "communication on Port %lu %lu (fuzzing start pending)\n",
+ "communication on node %lu %lu (fuzzing start pending)\n",
channel->GetName().v1, channel->GetName().v2);
channel->mBlockSendRecv = true;
}
return false;
}
+ MOZ_FUZZING_NYX_ABORT("Unreachable");
return true;
}
}
@@ -452,6 +519,11 @@ bool IPCFuzzController::ObserveIPCMessage(mozilla::ipc::NodeChannel* channel,
portSeqNos.insert_or_assign(
name, std::pair<int32_t, uint64_t>(aMessage.seqno(),
userMsgEv->sequence_num()));
+#ifdef FUZZ_DEBUG
+ MOZ_FUZZING_NYX_PRINTF(
+ "DEBUG: Port %lu %lu updated sequence number to %lu\n", name.v1,
+ name.v2, userMsgEv->sequence_num());
+#endif
portNodeName.insert_or_assign(name, channel->GetName());
}
@@ -520,18 +592,6 @@ bool IPCFuzzController::MakeTargetDecision(
uint8_t portIndex, uint8_t portInstanceIndex, uint8_t actorIndex,
uint16_t typeOffset, PortName* name, int32_t* seqno, uint64_t* fseqno,
int32_t* actorId, uint32_t* type, bool* is_cons, bool update) {
- // Every possible toplevel actor type has a fixed number that
- // we assign to it in the constructor of this class. Here, we
- // use the lower 6 bits to select this toplevel actor type.
- // This approach has the advantage that the tests will always
- // select the same toplevel actor type deterministically,
- // independent of the order they appeared and independent
- // of the type of fuzzing we are doing.
- auto portInstances = portNames[portIndex & 0x3f];
- if (!portInstances.size()) {
- return false;
- }
-
if (useLastActor) {
useLastActor--;
*name = lastActorPortName;
@@ -541,17 +601,26 @@ bool IPCFuzzController::MakeTargetDecision(
// Once we stop pinning to the last actor, we need to decide if we
// want to keep the pinning on the port itself. We use one of the
// unused upper bits of portIndex for this purpose.
- if (!useLastActor && (portIndex & (1 << 7))) {
- if (mIPCTriggerMsg == ipcDefaultTriggerMsg) {
- MOZ_FUZZING_NYX_PRINT(
- "DEBUG: MakeTargetDecision: Released pinning on last port.\n");
- useLastPortName = false;
- }
+ if (!useLastActor && !useLastPortNameAlways && (portIndex & (1 << 7))) {
+ MOZ_FUZZING_NYX_PRINT(
+ "DEBUG: MakeTargetDecision: Released pinning on last port.\n");
+ useLastPortName = false;
}
- } else if (useLastPortName) {
+ } else if (useLastPortName || useLastPortNameAlways) {
*name = lastActorPortName;
MOZ_FUZZING_NYX_PRINT("DEBUG: MakeTargetDecision: Pinned to last port.\n");
} else {
+ // Every possible toplevel actor type has a fixed number that
+ // we assign to it in the constructor of this class. Here, we
+ // use the lower 6 bits to select this toplevel actor type.
+ // This approach has the advantage that the tests will always
+ // select the same toplevel actor type deterministically,
+ // independent of the order they appeared and independent
+ // of the type of fuzzing we are doing.
+ auto portInstances = portNames[portIndex & 0x3f];
+ if (!portInstances.size()) {
+ return false;
+ }
*name = portInstances[portInstanceIndex % portInstances.size()];
}
@@ -580,7 +649,26 @@ bool IPCFuzzController::MakeTargetDecision(
bool isPreserveHeader = *type;
if (useLastActor) {
- actorIndex = actors.size() - 1;
+ if (maybeLastActorId) {
+ bool found = false;
+ for (actorIndex = 0; actorIndex < actors.size(); ++actorIndex) {
+ // Toplevel actors have a discrepancy here: Routing ID is -1 but the
+ // actor id provided through protocol->Id() is 0.
+ 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");
+ }
+ } else {
+ actorIndex = actors.size() - 1;
+ }
} else if (isPreserveHeader) {
// In preserveHeaderMode, we need to find an actor that matches the
// requested message type instead of any random actor.
@@ -592,6 +680,11 @@ bool IPCFuzzController::MakeTargetDecision(
ProtocolId wantedProtocolId = static_cast<ProtocolId>(maybeProtocolId);
std::vector<uint32_t> allowedIndices;
for (uint32_t i = 0; i < actors.size(); ++i) {
+ if (protoFilterTargetExcludeToplevel && !i) {
+ // Filter out the toplevel protocol at index 0
+ continue;
+ }
+
if (actors[i].second == wantedProtocolId) {
allowedIndices.push_back(i);
}
@@ -602,6 +695,14 @@ bool IPCFuzzController::MakeTargetDecision(
}
actorIndex = allowedIndices[actorIndex % allowedIndices.size()];
+ } else if (protoFilterTargetExcludeToplevel) {
+ // Filter out the toplevel protocol
+ if (actors.size() < 2) {
+ // We likely destroyed all other actors
+ return false;
+ }
+ actorIndex %= actors.size() - 1;
+ actorIndex++;
} else {
actorIndex %= actors.size();
}
@@ -735,11 +836,14 @@ NS_IMETHODIMP IPCFuzzController::IPCFuzzLoop::Run() {
auto portNameResult =
IPCFuzzController::instance().portNodeName.find(iter->first);
if (portNameResult->second ==
- IPCFuzzController::instance().targetNodeName) {
- MOZ_FUZZING_NYX_PRINT(
+ IPCFuzzController::instance().targetNodeName &&
+ IPCFuzzController::instance().mIPCTriggerMsg ==
+ ipcDefaultTriggerMsg) {
+ MOZ_FUZZING_NYX_PRINTF(
"ERROR: We should not have port map entries without a "
"corresponding "
- "entry in our actors map\n");
+ "entry in our actors map (Port %lu %lu)\n",
+ iter->first.v1, iter->first.v2);
MOZ_REALLY_CRASH(__LINE__);
} else {
iter = IPCFuzzController::instance().portSeqNos.erase(iter);
@@ -952,6 +1056,9 @@ NS_IMETHODIMP IPCFuzzController::IPCFuzzLoop::Run() {
msg->header()->type = msgType;
}
+ // Make sure we're not sending with LAZY_SEND
+ msg->header()->flags.mFlags &= ~IPC::Message::HeaderFlags::LAZY_SEND_BIT;
+
// Create the footer
auto messageEvent = MakeUnique<UserMessageEvent>(0);
messageEvent->set_port_name(new_port_name);
@@ -985,6 +1092,14 @@ NS_IMETHODIMP IPCFuzzController::IPCFuzzLoop::Run() {
msg->header()->flags, msg->header()->txid, msg->header()->num_handles);
#endif
+ if (!!getenv("MOZ_FUZZ_DEBUG")) {
+ MOZ_FUZZING_NYX_PRINTF(
+ "INFO: Flags: IsSync: %d IsReply: %d IsReplyError: %d IsConstructor: "
+ "%d IsRelay: %d IsLazySend: %d\n",
+ msg->is_sync(), msg->is_reply(), msg->is_reply_error(),
+ msg->is_constructor(), msg->is_relay(), msg->is_lazy_send());
+ }
+
// The number of messages we expect to see stopped.
expected_messages++;
@@ -1117,6 +1232,9 @@ void IPCFuzzController::SynchronizeOnMessageExecution(
Nyx::instance().handle_event("MOZ_TIMEOUT", nullptr, 0, nullptr);
MOZ_FUZZING_NYX_PRINT(
"ERROR: ======== END OF ITERATION (TIMEOUT) ========\n");
+ if (!!getenv("MOZ_FUZZ_CRASH_ON_TIMEOUT")) {
+ MOZ_DIAGNOSTIC_ASSERT(false, "IPCFuzzController Timeout");
+ }
Nyx::instance().release(
IPCFuzzController::instance().getMessageStopCount());
}
@@ -1241,6 +1359,7 @@ UniquePtr<IPC::Message> IPCFuzzController::replaceIPCMessage(
IPCFuzzController::instance().useLastActor = 0;
IPCFuzzController::instance().useLastPortName = false;
+ IPCFuzzController::instance().useLastPortNameAlways = false;
MOZ_FUZZING_NYX_DEBUG("DEBUG: Requesting data...\n");
@@ -1276,7 +1395,7 @@ UniquePtr<IPC::Message> IPCFuzzController::replaceIPCMessage(
ipchdr->payload_size = ipcMsgLen - sizeof(IPC::Message::Header);
if (Nyx::instance().is_replay()) {
- MOZ_FUZZING_NYX_PRINT("INFO: Replaying IPC packet with payload:\n");
+ MOZ_FUZZING_NYX_PRINT("INFO: Replaying single IPC packet with payload:\n");
for (uint32_t i = 0; i < ipcMsgLen - sizeof(IPC::Message::Header); ++i) {
if (i % 16 == 0) {
MOZ_FUZZING_NYX_PRINT("\n ");
@@ -1291,6 +1410,11 @@ UniquePtr<IPC::Message> IPCFuzzController::replaceIPCMessage(
UniquePtr<IPC::Message> msg(new IPC::Message(ipcMsgData, ipcMsgLen));
+ if (!!getenv("MOZ_FUZZ_DEBUG")) {
+ MOZ_FUZZING_NYX_PRINTF("INFO: Name: %s Target: %d\n", msg->name(),
+ msg->routing_id());
+ }
+
// This marks the message as a fuzzing message. Without this, it will
// be ignored by MessageTask and also not even scheduled by NodeChannel
// in asynchronous mode. We use this to ignore any IPC activity that
diff --git a/tools/fuzzing/ipc/IPCFuzzController.h b/tools/fuzzing/ipc/IPCFuzzController.h
index 756a68f38f..5c27443381 100644
--- a/tools/fuzzing/ipc/IPCFuzzController.h
+++ b/tools/fuzzing/ipc/IPCFuzzController.h
@@ -138,13 +138,24 @@ class IPCFuzzController {
// 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`.
+ // If set, `lastActorPortName` is valid and fuzzing is forever pinned to this
+ // port.
+ Atomic<bool> useLastPortNameAlways;
+
+ // If set, the toplevel actor will be from fuzzing.
+ Atomic<bool> protoFilterTargetExcludeToplevel;
+
+ // 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;
+ // If this is non-zero, we want a specific actor ID instead of the last.
+ Atomic<int32_t> maybeLastActorId;
+
// 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,
diff --git a/tools/fuzzing/smoke/smoke.py b/tools/fuzzing/smoke/smoke.py
index bfc7cb56cd..1a031a18f9 100644
--- a/tools/fuzzing/smoke/smoke.py
+++ b/tools/fuzzing/smoke/smoke.py
@@ -6,7 +6,7 @@
This script can be used to perform simple calls using `jsshell`
or whatever other tools you may add.
-The call is done via `taskcluster/ci/fuzzing/kind.yml` and
+The call is done via `taskcluster/kinds/fuzzing/kind.yml` and
files contained in the `target.jsshell.zip` and `target.fuzztest.tests.tar.gz`
build artifacts are downloaded to run things.