mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 13:48:44 +02:00
build: fuzzer that targets node::LoadEnvironment()
Refs: https://github.com/nodejs/node/pull/34761 Refs: https://github.com/nodejs/node/issues/33724 PR-URL: https://github.com/nodejs/node/pull/34844 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com>
This commit is contained in:
parent
b474901438
commit
de7a1abfc2
3 changed files with 192 additions and 0 deletions
43
node.gyp
43
node.gyp
|
@ -1257,6 +1257,49 @@
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
}, # fuzz_url
|
}, # 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',
|
'target_name': 'cctest',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
|
|
107
test/fuzzers/fuzz_env.cc
Normal file
107
test/fuzzers/fuzz_env.cc
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* A fuzzer focused on the node::LoadEnvironment() function.
|
||||||
|
*
|
||||||
|
* Code here has been inspired by the cctest test case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#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<node::ArrayBufferAllocator,
|
||||||
|
decltype(&node::FreeArrayBufferAllocator)>;
|
||||||
|
using TracingAgentUniquePtr = std::unique_ptr<node::tracing::Agent>;
|
||||||
|
using NodePlatformUniquePtr = std::unique_ptr<node::NodePlatform>;
|
||||||
|
|
||||||
|
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<std::string> node_argv{ "fuzz_env" };
|
||||||
|
std::vector<std::string> exec_argv;
|
||||||
|
std::vector<std::string> errors;
|
||||||
|
|
||||||
|
node::InitializeNodeWithArgs(&node_argv, &exec_argv, &errors);
|
||||||
|
|
||||||
|
tracing_agent = std::make_unique<node::tracing::Agent>();
|
||||||
|
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());
|
||||||
|
CHECK_NOT_NULL(isolate_);
|
||||||
|
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<v8::Context> context_ = node::NewContext(isolate);
|
||||||
|
context_->Enter();
|
||||||
|
|
||||||
|
node::IsolateData* isolate_data_ = node::CreateIsolateData(isolate, ¤t_loop,
|
||||||
|
platform.get());
|
||||||
|
std::vector<std::string> args(*argv, *argv + 1);
|
||||||
|
std::vector<std::string> 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;
|
||||||
|
std::string s(reinterpret_cast<const char*>(data2), size);
|
||||||
|
EnvTest(ffh.isolate_, (char*)s.c_str());
|
||||||
|
ffh.Teardown();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
42
test/fuzzers/fuzz_helper.h
Normal file
42
test/fuzzers/fuzz_helper.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
struct Argv {
|
||||||
|
public:
|
||||||
|
Argv() : Argv({"node", "-p", "process.version"}) {}
|
||||||
|
|
||||||
|
Argv(const std::initializer_list<const char*> &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<char**>(malloc(nr_args_ * sizeof(char*)));
|
||||||
|
argv_[0] = static_cast<char*>(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_;
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue