/src/node/test/fuzzers/fuzz_strings.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * A fuzzer focused on C string -> Javascript String. |
3 | | */ |
4 | | |
5 | | #include <stdlib.h> |
6 | | #include "js_native_api.h" |
7 | | #include "js_native_api_v8.h" |
8 | | #include "node.h" |
9 | | #include "node_platform.h" |
10 | | #include "node_internals.h" |
11 | | #include "node_api_internals.h" |
12 | | #include "node_url.h" |
13 | | #include "env-inl.h" |
14 | | #include "util-inl.h" |
15 | | #include "v8.h" |
16 | | #include "libplatform/libplatform.h" |
17 | | #include "aliased_buffer.h" |
18 | | #include "fuzz_helper.h" |
19 | | |
20 | | using node::AliasedBufferBase; |
21 | | |
22 | | /* General set up */ |
23 | | using ArrayBufferUniquePtr = std::unique_ptr<node::ArrayBufferAllocator, |
24 | | decltype(&node::FreeArrayBufferAllocator)>; |
25 | | using TracingAgentUniquePtr = std::unique_ptr<node::tracing::Agent>; |
26 | | using NodePlatformUniquePtr = std::unique_ptr<node::NodePlatform>; |
27 | | |
28 | | static TracingAgentUniquePtr tracing_agent; |
29 | | static NodePlatformUniquePtr platform; |
30 | | static uv_loop_t current_loop; |
31 | | static napi_env addon_env; |
32 | | |
33 | | inline napi_env NewEnv(v8::Local<v8::Context> context, |
34 | | const std::string& module_filename, |
35 | | int32_t module_api_version); |
36 | | |
37 | 0 | static void free_string(node_api_nogc_env env, void* data, void* hint) { |
38 | 0 | free(data); |
39 | 0 | } |
40 | | |
41 | 122k | extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { |
42 | 122k | uv_os_unsetenv("NODE_OPTIONS"); |
43 | 122k | std::vector<std::string> node_argv{ "fuzz_string_conversion" }; |
44 | 122k | std::vector<std::string> exec_argv; |
45 | 122k | std::vector<std::string> errors; |
46 | | |
47 | 122k | node::InitializeNodeWithArgs(&node_argv, &exec_argv, &errors); |
48 | | |
49 | 122k | tracing_agent = std::make_unique<node::tracing::Agent>(); |
50 | 122k | node::tracing::TraceEventHelper::SetAgent(tracing_agent.get()); |
51 | 122k | node::tracing::TracingController* tracing_controller = |
52 | 122k | tracing_agent->GetTracingController(); |
53 | 122k | CHECK_EQ(0, uv_loop_init(¤t_loop)); |
54 | 122k | static constexpr int kV8ThreadPoolSize = 4; |
55 | 122k | platform.reset( |
56 | 122k | new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); |
57 | 122k | v8::V8::InitializePlatform(platform.get()); |
58 | 122k | cppgc::InitializeProcess(platform->GetPageAllocator()); |
59 | 122k | v8::V8::Initialize(); |
60 | 122k | return 0; |
61 | 122k | } |
62 | | |
63 | | class FuzzerFixtureHelper { |
64 | | public: |
65 | | v8::Isolate* isolate_; |
66 | | ArrayBufferUniquePtr allocator; |
67 | | |
68 | | FuzzerFixtureHelper() |
69 | 122k | : allocator(ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), |
70 | 122k | &node::FreeArrayBufferAllocator)) { |
71 | 122k | isolate_ = NewIsolate(allocator.get(), ¤t_loop, platform.get()); |
72 | 122k | CHECK_NOT_NULL(isolate_); |
73 | 122k | isolate_->Enter(); |
74 | 122k | }; |
75 | | |
76 | 122k | void Teardown() { |
77 | 122k | platform->DrainTasks(isolate_); |
78 | 122k | isolate_->Exit(); |
79 | 122k | platform->UnregisterIsolate(isolate_); |
80 | 122k | isolate_->Dispose(); |
81 | 122k | isolate_ = nullptr; |
82 | 122k | } |
83 | | }; |
84 | | |
85 | 7.51k | void EnvTest(v8::Isolate* isolate_, char* env_string, size_t size) { |
86 | 7.51k | const v8::HandleScope handle_scope(isolate_); |
87 | 7.51k | Argv argv; |
88 | | |
89 | 7.51k | node::EnvironmentFlags::Flags flags = node::EnvironmentFlags::kDefaultFlags; |
90 | 7.51k | auto isolate = handle_scope.GetIsolate(); |
91 | 7.51k | v8::Local<v8::Context> context_ = node::NewContext(isolate); |
92 | 7.51k | context_->Enter(); |
93 | | |
94 | 7.51k | node::IsolateData* isolate_data_ = node::CreateIsolateData(isolate, ¤t_loop, |
95 | 7.51k | platform.get()); |
96 | 7.51k | std::vector<std::string> args(*argv, *argv + 1); |
97 | 7.51k | std::vector<std::string> exec_args(*argv, *argv + 1); |
98 | 7.51k | node::Environment* environment_ = node::CreateEnvironment(isolate_data_, |
99 | 7.51k | context_, args, exec_args, flags); |
100 | 7.51k | node::Environment* envi = environment_; |
101 | 7.51k | SetProcessExitHandler(envi, [&](node::Environment* env_, int exit_code) { |
102 | 0 | node::Stop(envi); |
103 | 0 | }); |
104 | 7.51k | node::LoadEnvironment(envi, ""); |
105 | | |
106 | | |
107 | 7.51k | napi_addon_register_func init = [](napi_env env, napi_value exports) { |
108 | 7.51k | addon_env = env; |
109 | 7.51k | return exports; |
110 | 7.51k | }; |
111 | 7.51k | v8::Local<v8::Object> module_obj = v8::Object::New(isolate); |
112 | 7.51k | v8::Local<v8::Object> exports_obj = v8::Object::New(isolate); |
113 | 7.51k | napi_module_register_by_symbol( |
114 | 7.51k | exports_obj, module_obj, context_, init, NAPI_VERSION); |
115 | 7.51k | size_t copied1, copied2; |
116 | 7.51k | bool copied3; |
117 | 7.51k | napi_value output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12; |
118 | 7.51k | char *buf1 = (char *)malloc(size); |
119 | 7.51k | char *buf2 = (char *)malloc(size); |
120 | 7.51k | napi_create_string_utf8(addon_env, env_string, size, &output1); |
121 | 7.51k | napi_get_value_string_utf8(addon_env, output1, buf1, size, &copied1); |
122 | 7.51k | napi_create_string_latin1(addon_env, env_string, size, &output2); |
123 | 7.51k | napi_get_value_string_latin1(addon_env, output2, buf2, size, &copied2); |
124 | | |
125 | 7.51k | char* string_copy; |
126 | 7.51k | const size_t actual_length = |
127 | 7.51k | (size == NAPI_AUTO_LENGTH ? strlen(env_string) : size); |
128 | 7.51k | const size_t length_bytes = (actual_length + 1) * sizeof(*string_copy); |
129 | 7.51k | string_copy = (char *)malloc(length_bytes); |
130 | 7.51k | memcpy(string_copy, env_string, length_bytes); |
131 | 7.51k | string_copy[actual_length] = 0; |
132 | | |
133 | | //node_api_create_external_string_latin1(addon_env, string_copy, size, free_string, NULL, output3, &copied3); |
134 | | |
135 | 7.51k | node_api_symbol_for(addon_env, env_string, size, &output4); |
136 | | |
137 | 7.51k | napi_set_named_property(addon_env, output1, env_string, output2); // could use other napi_values than 'output1' |
138 | | |
139 | 7.51k | napi_get_named_property(addon_env, output1, env_string, &output6); // could use other napi_values than 'output1' |
140 | | |
141 | 7.51k | napi_has_named_property(addon_env, output1, env_string, &copied3); // could use other napi_values than 'output1' |
142 | | |
143 | 7.51k | napi_get_property_names(addon_env, output1, &output7); // could use other napi_values than 'output1' |
144 | | |
145 | 7.51k | napi_has_property(addon_env, output1, output2, &copied3); // could use other napi_values than 'output1/2' |
146 | | |
147 | 7.51k | napi_get_property(addon_env, output1, output2, &output8); // could use other napi_values than 'output1/2' |
148 | | |
149 | 7.51k | napi_delete_property(addon_env, output1, output2, &copied3); // could use other napi_values than 'output1/2' |
150 | | |
151 | 7.51k | napi_has_own_property(addon_env, output1, output2, &copied3); // could use other napi_values than 'output1/2' |
152 | | |
153 | 7.51k | napi_create_type_error(addon_env, output1, output2, &output9); // could use other napi_values than 'output1/2' |
154 | | |
155 | 7.51k | napi_create_range_error(addon_env, output1, output2, &output10); // could use other napi_values than 'output1/2' |
156 | | |
157 | 7.51k | node_api_create_syntax_error(addon_env, output1, output2, &output11); // could use other napi_values than 'output1/2' |
158 | | |
159 | 7.51k | napi_run_script(addon_env, output2, &output12); // could use other napi_values than 'output2' |
160 | | |
161 | | //napi_is_array(addon_env, output1, copied3); // could use other napi_values than 'output1' |
162 | | |
163 | 7.51k | free(string_copy); |
164 | 7.51k | free(buf1); |
165 | 7.51k | free(buf2); |
166 | | |
167 | | // Cleanup! |
168 | 7.51k | node::FreeEnvironment(environment_); |
169 | 7.51k | node::FreeIsolateData(isolate_data_); |
170 | 7.51k | context_->Exit(); |
171 | 7.51k | } |
172 | | |
173 | 33.0k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) { |
174 | 33.0k | FuzzerFixtureHelper ffh; |
175 | 33.0k | std::string s(reinterpret_cast<const char*>(data2), size); |
176 | 33.0k | EnvTest(ffh.isolate_, (char*)s.c_str(), size); |
177 | 33.0k | ffh.Teardown(); |
178 | 33.0k | return 0; |
179 | 33.0k | } |