Skip to content

Instantly share code, notes, and snippets.

@n30m1nd
Last active May 10, 2022 12:01
Show Gist options
  • Save n30m1nd/a58652988bdef85ec5db1b4180dd39f0 to your computer and use it in GitHub Desktop.
Save n30m1nd/a58652988bdef85ec5db1b4180dd39f0 to your computer and use it in GitHub Desktop.
From 93c6087b83243b02f1dae28964732215782c5df4 Mon Sep 17 00:00:00 2001
From: n30m1nd <j******@gmail.com>
Date: Sat, 21 Mar 2020 14:09:14 +0000
Subject: [PATCH] Patch fuzzilli
---
BUILD.gn | 2 +
src/d8/cov.cc | 61 ++++++++++++++++++++++++
src/d8/cov.h | 6 +++
src/d8/d8.cc | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/d8/d8.h | 2 +
5 files changed, 197 insertions(+)
create mode 100644 src/d8/cov.cc
create mode 100644 src/d8/cov.h
diff --git a/src/api/api.cc b/src/api/api.cc
index 915a781f3a..d6bc6689fc 100644
--- a/src/api/api.cc
+++ b/src/api/api.cc
@@ -503,7 +503,8 @@ void Utils::ReportOOMFailure(i::Isolate* isolate, const char* location,
if (fatal_callback == nullptr) {
base::OS::PrintError("\n#\n# Fatal %s OOM in %s\n#\n\n",
is_heap_oom ? "javascript" : "process", location);
- base::OS::Abort();
+ exit(0);
+// base::OS::Abort();
} else {
fatal_callback(location,
is_heap_oom
diff --git a/BUILD.gn b/BUILD.gn
index 80cb4d61d5..bc42f63641 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -4279,6 +4279,8 @@ v8_executable("d8") {
sources = [
"src/d8/async-hooks-wrapper.cc",
"src/d8/async-hooks-wrapper.h",
+ "src/d8/cov.cc",
+ "src/d8/cov.h",
"src/d8/d8-console.cc",
"src/d8/d8-console.h",
"src/d8/d8-js.cc",
diff --git a/src/d8/cov.cc b/src/d8/cov.cc
new file mode 100644
index 0000000000..8b5e9cf0ca
--- /dev/null
+++ b/src/d8/cov.cc
@@ -0,0 +1,61 @@
+#include <inttypes.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define SHM_SIZE 0x100000
+#define MAX_EDGES ((SHM_SIZE - 4) * 8)
+
+struct shmem_data {
+ uint32_t num_edges;
+ unsigned char edges[];
+};
+
+struct shmem_data* shmem;
+
+uint32_t *__edges_start, *__edges_stop;
+void __sanitizer_cov_reset_edgeguards() {
+ uint32_t N = 0;
+ for (uint32_t *x = __edges_start; x < __edges_stop && N < MAX_EDGES; x++)
+ *x = ++N;
+}
+
+extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) {
+ // Map the shared memory region
+ const char* shm_key = getenv("SHM_ID");
+ if (!shm_key) {
+ puts("[COV] no shared memory bitmap available, skipping");
+ shmem = (struct shmem_data*) malloc(SHM_SIZE);
+ } else {
+ int fd = shm_open(shm_key, O_RDWR, S_IREAD | S_IWRITE);
+ if (fd <= -1) {
+ fprintf(stderr, "[COV] Failed to open shared memory region\n");
+ _exit(-1);
+ }
+
+ shmem = (struct shmem_data*) mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (shmem == MAP_FAILED) {
+ fprintf(stderr, "[COV] Failed to mmap shared memory region\n");
+ _exit(-1);
+ }
+ }
+
+ __edges_start = start;
+ __edges_stop = stop;
+ __sanitizer_cov_reset_edgeguards();
+
+ shmem->num_edges = static_cast<uint32_t>(stop - start);
+ printf("[COV] edge counters initialized. Shared memory: %s with %u edges\n", shm_key, shmem->num_edges);
+}
+
+extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
+ if (!*guard) return;
+ uint32_t index = *guard - 1;
+ shmem->edges[index / 8] |= 1 << (index % 8);
+ *guard = 0; // if multiple threads are active, this can lead to crashes due to race conditions
+}
diff --git a/src/d8/cov.h b/src/d8/cov.h
new file mode 100644
index 0000000000..e6bdfb40b6
--- /dev/null
+++ b/src/d8/cov.h
@@ -0,0 +1,6 @@
+#ifndef V8_COV_H_
+#define V8_COV_H_
+
+void __sanitizer_cov_reset_edgeguards();
+
+#endif
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index 3f559e6b43..1fc2ed91cb 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -28,6 +28,7 @@
#include "src/base/platform/platform.h"
#include "src/base/platform/time.h"
#include "src/base/sys-info.h"
+#include "src/d8/cov.h"
#include "src/d8/d8-console.h"
#include "src/d8/d8-platforms.h"
#include "src/d8/d8.h"
@@ -77,6 +78,12 @@
#define CHECK(condition) assert(condition)
#endif
+// REPRL defines
+#define REPRL_CRFD 100
+#define REPRL_CWFD 101
+#define REPRL_DRFD 102
+#define REPRL_DWFD 103
+
#define TRACE_BS(...) \
do { \
if (i::FLAG_trace_backing_store) PrintF(__VA_ARGS__); \
@@ -88,6 +95,8 @@ namespace {
const int kMB = 1024 * 1024;
+bool reprl_mode = true;
+
const int kMaxSerializerMemoryUsage =
1 * kMB; // Arbitrary maximum for testing.
@@ -1730,6 +1739,49 @@ void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
.ToLocalChecked());
}
+// We have to assume that the fuzzer will be able to call this function e.g. by
+// enumerating the properties of the global object and eval'ing them. As such
+// this function is implemented in a way that requires passing some magic value
+// as first argument (with the idea being that the fuzzer won't be able to
+// generate this value) which then also acts as a selector for the operation
+// to perform.
+void Shell::Fuzzilli(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ HandleScope handle_scope(args.GetIsolate());
+
+ String::Utf8Value operation(args.GetIsolate(), args[0]);
+ if (*operation == nullptr) {
+ return;
+ }
+
+ if (strcmp(*operation, "FUZZILLI_CRASH") == 0) {
+ auto arg = args[1]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromMaybe(0);
+ switch (arg) {
+ case 0:
+ *((int*)0x41414141) = 0x1337;
+ break;
+ case 1:
+ CHECK(0);
+ break;
+ default:
+ DCHECK(false);
+ break;
+ }
+ } else if (strcmp(*operation, "FUZZILLI_PRINT") == 0) {
+ static FILE* fzliout = fdopen(REPRL_DWFD, "w");
+ if (!fzliout) {
+ fprintf(stderr, "Fuzzer output channel not available, printing to stdout instead\n");
+ fzliout = stdout;
+ }
+
+ String::Utf8Value string(args.GetIsolate(), args[1]);
+ if (*string == nullptr) {
+ return;
+ }
+ fprintf(fzliout, "%s\n", *string);
+ fflush(fzliout);
+ }
+}
+
void Shell::ReportException(Isolate* isolate, Local<v8::Message> message,
Local<v8::Value> exception_obj) {
HandleScope handle_scope(isolate);
@@ -1994,6 +2046,11 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
AddOSMethods(isolate, os_templ);
global_template->Set(isolate, "os", os_templ);
+ global_template->Set(
+ String::NewFromUtf8(isolate, "fuzzilli", NewStringType::kNormal)
+ .ToLocalChecked(),
+ FunctionTemplate::New(isolate, Fuzzilli), PropertyAttribute::DontEnum);
+
if (i::FLAG_expose_async_hooks) {
Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate);
async_hooks_templ->Set(
@@ -2065,6 +2122,18 @@ void Shell::Initialize(Isolate* isolate, D8Console* console,
isolate->SetHostInitializeImportMetaObjectCallback(
Shell::HostInitializeImportMetaObject);
+ // REPRL: let parent know we are ready
+ char helo[] = "HELO";
+ if (write(REPRL_CWFD, helo, 4) != 4 ||
+ read(REPRL_CRFD, helo, 4) != 4) {
+ reprl_mode = false;
+ }
+
+ if (memcmp(helo, "HELO", 4) != 0) {
+ fprintf(stderr, "Invalid response from parent\n");
+ _exit(-1);
+ }
+
debug::SetConsoleDelegate(isolate, console);
}
@@ -2587,6 +2656,38 @@ bool SourceGroup::Execute(Isolate* isolate) {
break;
}
continue;
+ } else if (strcmp(arg, "--reprl") == 0) {
+ HandleScope handle_scope(isolate);
+ Local<String> file_name =
+ String::NewFromUtf8(isolate, "fuzzcode.js", NewStringType::kNormal)
+ .ToLocalChecked();
+
+ size_t script_size;
+ CHECK(read(REPRL_CRFD, &script_size, 8) == 8);
+ char* buffer = new char[script_size + 1];
+ char* ptr = buffer;
+ size_t remaining = script_size;
+ while (remaining > 0) {
+ ssize_t rv = read(REPRL_DRFD, ptr, remaining);
+ CHECK(rv >= 0);
+ remaining -= rv;
+ ptr += rv;
+ }
+ buffer[script_size] = 0;
+
+ Local<String> source =
+ String::NewFromUtf8(isolate, buffer, NewStringType::kNormal)
+ .ToLocalChecked();
+ delete [] buffer;
+ Shell::set_script_executed();
+ if (!Shell::ExecuteString(isolate, source, file_name,
+ Shell::kNoPrintResult, Shell::kReportExceptions,
+ Shell::kNoProcessMessageQueue)) {
+ success = false;
+ break;
+ }
+ ++i;
+ continue;
} else if (arg[0] == '-') {
// Ignore other options. They have been parsed already.
continue;
@@ -3037,6 +3138,8 @@ bool Shell::SetOptions(int argc, char* argv[]) {
current->Begin(argv, i + 1);
} else if (strcmp(str, "--module") == 0) {
// Pass on to SourceGroup, which understands this option.
+ } else if (strcmp(str, "--reprl") == 0) {
+ // Pass on to SourceGroup, which understands this option.
} else if (strncmp(str, "--", 2) == 0) {
printf("Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
@@ -3621,6 +3724,20 @@ int Shell::Main(int argc, char* argv[]) {
Initialize(isolate, &console);
PerIsolateData data(isolate);
+ // REPRL.
+ do {
+ // Keep original indention here for easier diffing against newer versions.
+ if (reprl_mode) {
+ unsigned action = 0;
+ ssize_t nread = read(REPRL_CRFD, &action, 4);
+ if (nread != 4 || action != 'cexe') {
+ fprintf(stderr, "Unknown action: %u\n", action);
+ _exit(-1);
+ }
+ }
+
+ result = 0;
+
if (options.trace_enabled) {
platform::tracing::TraceConfig* trace_config;
if (options.trace_config) {
@@ -3725,8 +3842,17 @@ int Shell::Main(int argc, char* argv[]) {
evaluation_context_.Reset();
stringify_function_.Reset();
CollectGarbage(isolate);
+
+ // REPRL: send result to parent and reset edge guards
+ if (reprl_mode) {
+ int status = result << 8;
+ CHECK(write(REPRL_CWFD, &status, 4) == 4);
+ __sanitizer_cov_reset_edgeguards();
+ }
+ } while (reprl_mode);
}
OnExit(isolate);
+
V8::Dispose();
V8::ShutdownPlatform();
diff --git a/src/d8/d8.h b/src/d8/d8.h
index f4582b2a4b..b712001936 100644
--- a/src/d8/d8.h
+++ b/src/d8/d8.h
@@ -433,6 +433,8 @@ class Shell : public i::AllStatic {
Local<Module> module,
Local<Object> meta);
+ static void Fuzzilli(const v8::FunctionCallbackInfo<v8::Value>& args);
+
// Data is of type DynamicImportData*. We use void* here to be able
// to conform with MicrotaskCallback interface and enqueue this
// function in the microtask queue.
--
2.26.0.rc2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment