Bug 1764259 - [Fuzzing] Nyx replay mode. r=truber

Differential Revision: https://phabricator.services.mozilla.com/D143458
This commit is contained in:
Christian Holler 2022-04-14 12:10:14 +00:00
parent cde0054620
commit 8e5b003502
3 changed files with 131 additions and 4 deletions

View File

@ -29,14 +29,18 @@
});
# endif
# define MOZ_FUZZING_HANDLE_CRASH_EVENT2(aType, aReason) \
do { \
nyx_handle_event(aType, __FILE__, __LINE__, aReason); \
# define MOZ_FUZZING_HANDLE_CRASH_EVENT2(aType, aReason) \
do { \
if (nyx_handle_event) { \
nyx_handle_event(aType, __FILE__, __LINE__, aReason); \
} \
} while (false)
# define MOZ_FUZZING_HANDLE_CRASH_EVENT4(aType, aFilename, aLine, aReason) \
do { \
nyx_handle_event(aType, aFilename, aLine, aReason); \
if (nyx_handle_event) { \
nyx_handle_event(aType, aFilename, aLine, aReason); \
} \
} while (false)
# define MOZ_FUZZING_NYX_PRINT(aMsg) \

View File

@ -5,7 +5,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Assertions.h"
#include "mozilla/Vector.h"
#include "mozilla/fuzzing/Nyx.h"
#include "prinrval.h"
#include "prthread.h"
#include <algorithm>
#include <fstream>
#include <unistd.h>
namespace mozilla {
namespace fuzzing {
@ -47,6 +55,72 @@ void Nyx::start(void) {
MOZ_RELEASE_ASSERT(!mInited);
mInited = true;
// Check if we are in replay mode.
char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE");
if (testFilePtr) {
mReplayMode = true;
MOZ_FUZZING_NYX_PRINT("[Replay Mode] Reading data file...\n");
std::string testFile(testFilePtr);
std::ifstream is;
is.open(testFile, std::ios::binary);
uint64_t chksum, num_ops, num_data, op_offset, data_offset;
// If only C++ supported streaming operators on binary files...
is.read(reinterpret_cast<char*>(&chksum), sizeof(uint64_t));
is.read(reinterpret_cast<char*>(&num_ops), sizeof(uint64_t));
is.read(reinterpret_cast<char*>(&num_data), sizeof(uint64_t));
is.read(reinterpret_cast<char*>(&op_offset), sizeof(uint64_t));
is.read(reinterpret_cast<char*>(&data_offset), sizeof(uint64_t));
if (!is.good()) {
MOZ_FUZZING_NYX_PRINT("[Replay Mode] Error reading input file.\n");
_exit(1);
}
is.seekg(data_offset);
// The data chunks we receive through Nyx are stored in the data
// section of the testfile as chunks prefixed with a 16-bit data
// length. We read all chunks and store them away to simulate how
// we originally received the data via Nyx.
while (is.good()) {
uint16_t pktsize;
is.read(reinterpret_cast<char*>(&pktsize), sizeof(uint16_t));
if (!is.good()) {
break;
}
auto buffer = new Vector<uint8_t>();
buffer->initLengthUninitialized(pktsize);
is.read(reinterpret_cast<char*>(buffer->begin()), buffer->length());
MOZ_FUZZING_NYX_PRINTF("[Replay Mode] Read data packet of size %zu\n",
buffer->length());
mReplayBuffers.push_back(buffer);
}
if (!mReplayBuffers.size()) {
MOZ_FUZZING_NYX_PRINT("[Replay Mode] Error: No buffers read.\n");
_exit(1);
}
is.close();
if (!!getenv("MOZ_FUZZ_WAIT_BEFORE_REPLAY")) {
// This can be useful in some cases to reproduce intermittent issues.
PR_Sleep(PR_MillisecondsToInterval(5000));
}
return;
}
NYX_CHECK_API(nyx_start);
NYX_CHECK_API(nyx_get_next_fuzz_data);
NYX_CHECK_API(nyx_release);
@ -66,19 +140,58 @@ bool Nyx::is_enabled(const char* identifier) {
return true;
}
bool Nyx::is_replay() { return mReplayMode; }
uint32_t Nyx::get_data(uint8_t* data, uint32_t size) {
MOZ_RELEASE_ASSERT(mInited);
if (mReplayMode) {
if (!mReplayBuffers.size()) {
return 0xFFFFFFFF;
}
Vector<uint8_t>* buffer = mReplayBuffers.front();
mReplayBuffers.pop_front();
size = std::min(size, (uint32_t)buffer->length());
memcpy(data, buffer->begin(), size);
delete buffer;
return size;
}
return nyx_get_next_fuzz_data(data, size);
}
void Nyx::release(uint32_t iterations) {
MOZ_RELEASE_ASSERT(mInited);
if (mReplayMode) {
MOZ_FUZZING_NYX_PRINT("[Replay Mode] Nyx::release() called.\n");
// If we reach this point in replay mode, we are essentially done.
// Let's wait a bit further for things to settle and then exit.
PR_Sleep(PR_MillisecondsToInterval(5000));
_exit(1);
return;
}
nyx_release(iterations);
}
void Nyx::handle_event(const char* type, const char* file, int line,
const char* reason) {
MOZ_RELEASE_ASSERT(mInited);
if (mReplayMode) {
MOZ_FUZZING_NYX_PRINTF(
"[Replay Mode] Nyx::handle_event() called: %s at %s:%d : %s\n", type,
file, line, reason);
return;
}
nyx_handle_event(type, file, line, reason);
}

View File

@ -9,6 +9,7 @@
#include <stdint.h>
#include <atomic>
#include <list>
#ifndef NYX_DISALLOW_COPY_AND_ASSIGN
# define NYX_DISALLOW_COPY_AND_ASSIGN(T) \
@ -17,6 +18,11 @@
#endif
namespace mozilla {
class MallocAllocPolicy;
template <class T, size_t MinInlineCapacity, class AllocPolicy>
class Vector;
namespace fuzzing {
class Nyx {
@ -26,6 +32,7 @@ class Nyx {
void start(void);
bool started(void);
bool is_enabled(const char* identifier);
bool is_replay();
uint32_t get_data(uint8_t* data, uint32_t size);
void release(uint32_t iterations = 1);
void handle_event(const char* type, const char* file, int line,
@ -34,6 +41,9 @@ class Nyx {
private:
std::atomic<bool> mInited;
std::atomic<bool> mReplayMode;
std::list<Vector<uint8_t, 0, MallocAllocPolicy>*> mReplayBuffers;
Nyx();
NYX_DISALLOW_COPY_AND_ASSIGN(Nyx);
};