Last active
May 10, 2022 12:01
-
-
Save n30m1nd/a58652988bdef85ec5db1b4180dd39f0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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