From 1570339f3f7b7326f7195bb435bbb19a3103bd61 Mon Sep 17 00:00:00 2001 From: davkor Date: Wed, 19 Aug 2020 22:02:14 +0100 Subject: [PATCH 1/5] build: adds a new fuzzer that targets node::LoadEnvironment() Refs: https://github.com/nodejs/node/pull/34761 Refs: https://github.com/nodejs/node/issues/33724 --- node.gyp | 43 +++++++++++++ test/fuzzers/fuzz_env.cc | 117 ++++++++++++++++++++++++++++++++++++ test/fuzzers/fuzz_helper.cc | 42 +++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 test/fuzzers/fuzz_env.cc create mode 100644 test/fuzzers/fuzz_helper.cc diff --git a/node.gyp b/node.gyp index 22c270123f1658..05e67b16d8b03c 100644 --- a/node.gyp +++ b/node.gyp @@ -1203,6 +1203,49 @@ }], ], }, # fuzz_url + { # fuzz_env + 'target_name': 'fuzz_env', + 'type': 'executable', + 'dependencies': [ + '<(node_lib_target_name)', + 'deps/histogram/histogram.gyp:histogram', + 'deps/uvwasi/uvwasi.gyp:uvwasi', + 'node_dtrace_header', + 'node_dtrace_ustack', + 'node_dtrace_provider', + ], + 'includes': [ + 'node.gypi' + ], + 'include_dirs': [ + 'src', + 'tools/msvs/genfiles', + 'deps/v8/include', + 'deps/cares/include', + 'deps/uv/include', + 'deps/uvwasi/include', + 'test/cctest', + ], + 'defines': [ + 'NODE_ARCH="<(target_arch)"', + 'NODE_PLATFORM="<(OS)"', + 'NODE_WANT_INTERNALS=1', + ], + 'sources': [ + 'src/node_snapshot_stub.cc', + 'src/node_code_cache_stub.cc', + 'test/fuzzers/fuzz_env.cc', + ], + 'conditions': [ + ['OS=="linux"', { + 'ldflags': [ '-fsanitize=fuzzer' ] + }], + # Ensure that ossfuzz flag has been set and that we are on Linux + [ 'OS!="linux" or ossfuzz!="true"', { + 'type': 'none', + }], + ], + }, # fuzz_env { 'target_name': 'cctest', 'type': 'executable', diff --git a/test/fuzzers/fuzz_env.cc b/test/fuzzers/fuzz_env.cc new file mode 100644 index 00000000000000..0a7c3f392fe385 --- /dev/null +++ b/test/fuzzers/fuzz_env.cc @@ -0,0 +1,117 @@ +/* + * A fuzzer focused on the node::LoadEnvironment() function. + * + * Code here has been inspired by the cctest test case. + */ + +#include +#include "node.h" +#include "node_platform.h" +#include "node_internals.h" +#include "env-inl.h" +#include "util-inl.h" +#include "v8.h" +#include "libplatform/libplatform.h" +#include "aliased_buffer.h" +#include "fuzz_helper.h" + +using node::AliasedBufferBase; + +/* General set up */ +using ArrayBufferUniquePtr = std::unique_ptr; +using TracingAgentUniquePtr = std::unique_ptr; +using NodePlatformUniquePtr = std::unique_ptr; + +static TracingAgentUniquePtr tracing_agent; +static NodePlatformUniquePtr platform; +static uv_loop_t current_loop; + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + uv_os_unsetenv("NODE_OPTIONS"); + std::vector node_argv{ "fuzz_env" }; + std::vector exec_argv; + std::vector errors; + + node::InitializeNodeWithArgs(&node_argv, &exec_argv, &errors); + + tracing_agent = std::make_unique(); + node::tracing::TraceEventHelper::SetAgent(tracing_agent.get()); + node::tracing::TracingController* tracing_controller = + tracing_agent->GetTracingController(); + CHECK_EQ(0, uv_loop_init(¤t_loop)); + static constexpr int kV8ThreadPoolSize = 4; + platform.reset( + new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); + v8::V8::InitializePlatform(platform.get()); + v8::V8::Initialize(); + return 0; +} + +class FuzzerFixtureHelper { +public: + v8::Isolate* isolate_; + ArrayBufferUniquePtr allocator; + + FuzzerFixtureHelper() + : allocator(ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), + &node::FreeArrayBufferAllocator)) + { + isolate_ = NewIsolate(allocator.get(), ¤t_loop, + platform.get()); + isolate_->Enter(); + }; + + void Teardown() + { + platform->DrainTasks(isolate_); + isolate_->Exit(); + platform->UnregisterIsolate(isolate_); + isolate_->Dispose(); + isolate_ = nullptr; + } +}; + +void EnvTest(v8::Isolate* isolate_, char* env_string) +{ + const v8::HandleScope handle_scope(isolate_); + Argv argv; + + node::EnvironmentFlags::Flags flags = node::EnvironmentFlags::kDefaultFlags; + auto isolate = handle_scope.GetIsolate(); + v8::Local context_ = node::NewContext(isolate); + context_->Enter(); + + node::IsolateData* isolate_data_ = node::CreateIsolateData(isolate, ¤t_loop, + platform.get()); + std::vector args(*argv, *argv + 1); + std::vector exec_args(*argv, *argv + 1); + node::Environment* environment_ = node::CreateEnvironment(isolate_data_, + context_, args, exec_args, flags); + node::Environment* envi = environment_; + SetProcessExitHandler(envi, [&](node::Environment* env_, int exit_code) { + node::Stop(envi); + }); + node::LoadEnvironment(envi, env_string); + + // Cleanup! + node::FreeEnvironment(environment_); + node::FreeIsolateData(isolate_data_); + context_->Exit(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) +{ + FuzzerFixtureHelper ffh; + + char* new_string = (char*)malloc(size + 1); + new_string[size] = '\0'; + memcpy(new_string, data2, size); + EnvTest(ffh.isolate_, new_string); + free(new_string); + + ffh.Teardown(); + return 0; +} + diff --git a/test/fuzzers/fuzz_helper.cc b/test/fuzzers/fuzz_helper.cc new file mode 100644 index 00000000000000..707a8183dbd274 --- /dev/null +++ b/test/fuzzers/fuzz_helper.cc @@ -0,0 +1,42 @@ +struct Argv { + public: + Argv() : Argv({"node", "-p", "process.version"}) {} + + Argv(const std::initializer_list &args) { + nr_args_ = args.size(); + int total_len = 0; + for (auto it = args.begin(); it != args.end(); ++it) { + total_len += strlen(*it) + 1; + } + argv_ = static_cast(malloc(nr_args_ * sizeof(char*))); + argv_[0] = static_cast(malloc(total_len)); + int i = 0; + int offset = 0; + for (auto it = args.begin(); it != args.end(); ++it, ++i) { + int len = strlen(*it) + 1; + snprintf(argv_[0] + offset, len, "%s", *it); + // Skip argv_[0] as it points the correct location already + if (i > 0) { + argv_[i] = argv_[0] + offset; + } + offset += len; + } + } + + ~Argv() { + free(argv_[0]); + free(argv_); + } + + int nr_args() const { + return nr_args_; + } + + char** operator*() const { + return argv_; + } + + private: + char** argv_; + int nr_args_; +}; From 4df0816cd59e56790c1d355b7a7ef4b2715849e9 Mon Sep 17 00:00:00 2001 From: davkor Date: Wed, 19 Aug 2020 22:18:17 +0100 Subject: [PATCH 2/5] build: rename cc file to header file. --- test/fuzzers/{fuzz_helper.cc => fuzz_helper.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/fuzzers/{fuzz_helper.cc => fuzz_helper.h} (100%) diff --git a/test/fuzzers/fuzz_helper.cc b/test/fuzzers/fuzz_helper.h similarity index 100% rename from test/fuzzers/fuzz_helper.cc rename to test/fuzzers/fuzz_helper.h From 2a6cda5610e149850cd3b441a5ab977103e6f5d8 Mon Sep 17 00:00:00 2001 From: davkor Date: Thu, 20 Aug 2020 22:39:01 +0100 Subject: [PATCH 3/5] build: Resolves the comments from bnoordhuis. --- test/fuzzers/fuzz_env.cc | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/test/fuzzers/fuzz_env.cc b/test/fuzzers/fuzz_env.cc index 0a7c3f392fe385..78c169e9c57d96 100644 --- a/test/fuzzers/fuzz_env.cc +++ b/test/fuzzers/fuzz_env.cc @@ -27,8 +27,7 @@ static TracingAgentUniquePtr tracing_agent; static NodePlatformUniquePtr platform; static uv_loop_t current_loop; -extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) -{ +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { uv_os_unsetenv("NODE_OPTIONS"); std::vector node_argv{ "fuzz_env" }; std::vector exec_argv; @@ -56,10 +55,10 @@ class FuzzerFixtureHelper { FuzzerFixtureHelper() : allocator(ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), - &node::FreeArrayBufferAllocator)) + &node::FreeArrayBufferAllocator)) { - isolate_ = NewIsolate(allocator.get(), ¤t_loop, - platform.get()); + isolate_ = NewIsolate(allocator.get(), ¤t_loop, platform.get()); + CHECK_NOT_NULL(isolate_); isolate_->Enter(); }; @@ -104,13 +103,8 @@ void EnvTest(v8::Isolate* isolate_, char* env_string) extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) { FuzzerFixtureHelper ffh; - - char* new_string = (char*)malloc(size + 1); - new_string[size] = '\0'; - memcpy(new_string, data2, size); - EnvTest(ffh.isolate_, new_string); - free(new_string); - + std::string s(reinterpret_cast(data2), size); + EnvTest(ffh.isolate_, s.c_str()); ffh.Teardown(); return 0; } From 9735bfbe8db89bff8206150f00736ad1ed0b1454 Mon Sep 17 00:00:00 2001 From: davkor Date: Thu, 20 Aug 2020 22:48:34 +0100 Subject: [PATCH 4/5] build: Fix remaining curly-bracket notation. --- test/fuzzers/fuzz_env.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/fuzzers/fuzz_env.cc b/test/fuzzers/fuzz_env.cc index 78c169e9c57d96..a99853f3498e95 100644 --- a/test/fuzzers/fuzz_env.cc +++ b/test/fuzzers/fuzz_env.cc @@ -55,15 +55,13 @@ class FuzzerFixtureHelper { FuzzerFixtureHelper() : allocator(ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), - &node::FreeArrayBufferAllocator)) - { + &node::FreeArrayBufferAllocator)) { isolate_ = NewIsolate(allocator.get(), ¤t_loop, platform.get()); CHECK_NOT_NULL(isolate_); isolate_->Enter(); }; - void Teardown() - { + void Teardown() { platform->DrainTasks(isolate_); isolate_->Exit(); platform->UnregisterIsolate(isolate_); @@ -72,8 +70,7 @@ class FuzzerFixtureHelper { } }; -void EnvTest(v8::Isolate* isolate_, char* env_string) -{ +void EnvTest(v8::Isolate* isolate_, char* env_string) { const v8::HandleScope handle_scope(isolate_); Argv argv; @@ -100,8 +97,7 @@ void EnvTest(v8::Isolate* isolate_, char* env_string) context_->Exit(); } -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) -{ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) { FuzzerFixtureHelper ffh; std::string s(reinterpret_cast(data2), size); EnvTest(ffh.isolate_, s.c_str()); From 3db21a0bc0afc1efd98ea07d97f7d2cb16eda21f Mon Sep 17 00:00:00 2001 From: davkor Date: Thu, 20 Aug 2020 23:29:36 +0100 Subject: [PATCH 5/5] build: Fix a typecast so the compiler wont complain. --- test/fuzzers/fuzz_env.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzzers/fuzz_env.cc b/test/fuzzers/fuzz_env.cc index a99853f3498e95..92af0bcb30e660 100644 --- a/test/fuzzers/fuzz_env.cc +++ b/test/fuzzers/fuzz_env.cc @@ -100,7 +100,7 @@ void EnvTest(v8::Isolate* isolate_, char* env_string) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) { FuzzerFixtureHelper ffh; std::string s(reinterpret_cast(data2), size); - EnvTest(ffh.isolate_, s.c_str()); + EnvTest(ffh.isolate_, (char*)s.c_str()); ffh.Teardown(); return 0; }