/src/node/test/fuzzers/fuzz_sign_verify.cc
Line | Count | Source |
1 | | /* |
2 | | * A fuzzer focused on the node::LoadEnvironment() function. |
3 | | * |
4 | | * Code here has been inspired by the cctest test case. |
5 | | */ |
6 | | |
7 | | #include <stdlib.h> |
8 | | #include "node.h" |
9 | | #include "node_platform.h" |
10 | | #include "node_internals.h" |
11 | | #include "env-inl.h" |
12 | | #include "util-inl.h" |
13 | | #include "v8.h" |
14 | | #include "libplatform/libplatform.h" |
15 | | #include "aliased_buffer.h" |
16 | | #include "fuzz_helper.h" |
17 | | #include <fuzzer/FuzzedDataProvider.h> |
18 | | #include <cstdio> |
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 | | |
32 | 132k | extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { |
33 | 132k | uv_os_unsetenv("NODE_OPTIONS"); |
34 | 132k | std::vector<std::string> node_argv{ "fuzz_env" }; |
35 | 132k | std::vector<std::string> exec_argv; |
36 | 132k | std::vector<std::string> errors; |
37 | | |
38 | 132k | node::InitializeNodeWithArgs(&node_argv, &exec_argv, &errors); |
39 | | |
40 | 132k | tracing_agent = std::make_unique<node::tracing::Agent>(); |
41 | 132k | node::tracing::TraceEventHelper::SetAgent(tracing_agent.get()); |
42 | 132k | node::tracing::TracingController* tracing_controller = |
43 | 132k | tracing_agent->GetTracingController(); |
44 | 132k | CHECK_EQ(0, uv_loop_init(¤t_loop)); |
45 | 132k | static constexpr int kV8ThreadPoolSize = 4; |
46 | 132k | platform.reset( |
47 | 132k | new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); |
48 | 132k | v8::V8::InitializePlatform(platform.get()); |
49 | 132k | cppgc::InitializeProcess(platform->GetPageAllocator()); |
50 | 132k | v8::V8::Initialize(); |
51 | 132k | return 0; |
52 | 132k | } |
53 | | |
54 | | class FuzzerFixtureHelper { |
55 | | public: |
56 | | v8::Isolate* isolate_; |
57 | | ArrayBufferUniquePtr allocator; |
58 | | |
59 | | FuzzerFixtureHelper() |
60 | 134k | : allocator(ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), |
61 | 134k | &node::FreeArrayBufferAllocator)) { |
62 | 134k | isolate_ = NewIsolate(allocator.get(), ¤t_loop, platform.get()); |
63 | 134k | CHECK_NOT_NULL(isolate_); |
64 | 134k | isolate_->Enter(); |
65 | 134k | }; |
66 | | |
67 | 134k | void Teardown() { |
68 | 134k | platform->DrainTasks(isolate_); |
69 | 134k | isolate_->Exit(); |
70 | 134k | platform->UnregisterIsolate(isolate_); |
71 | 134k | isolate_->Dispose(); |
72 | 134k | isolate_ = nullptr; |
73 | 134k | } |
74 | | }; |
75 | | |
76 | | std::string W1 = |
77 | | "var crypto = require(\"crypto\");\n" |
78 | | "var eol = require('os').EOL;\n" |
79 | | "\n" |
80 | | "function RSASign(algorithm, privateKey, data) {\n" |
81 | | " const sign = crypto.createSign(algorithm);\n" |
82 | | " sign.update(data);\n" |
83 | | " var sig = sign.sign(privateKey, 'hex');\n" |
84 | | " return sig;\n" |
85 | | "}\n" |
86 | | "function RSAVerify(algorithm, publicKey, signature, data) {\n" |
87 | | " const verify = crypto.createVerify(algorithm);\n" |
88 | | " verify.update(data);\n" |
89 | | " var _ = verify.verify(publicKey, signature,'hex');\n" |
90 | | "}\n" |
91 | | "function getAlgorithm(index) {\n" |
92 | | " var allAlgorithms = crypto.getHashes();\n" |
93 | | " return allAlgorithms[index\%allAlgorithms.length];\n" |
94 | | "}\n"; |
95 | | |
96 | | std::string W2 = "var pubStr = '"; |
97 | | //RANDOM |
98 | | std::string W3 = "';\n" |
99 | | "var p = '"; |
100 | | //RANDOM |
101 | | std::string W4 = "';\n" |
102 | | "var privateKey = '-----BEGIN PRIVATE KEY-----' + eol + p + eol + '-----END PRIVATE KEY-----';\n" |
103 | | "var publicKey= '-----BEGIN PUBLIC KEY-----' + eol + pubStr + eol + '-----END PUBLIC KEY-----';\n" |
104 | | "var dataToSign = \""; |
105 | | //RANDOM |
106 | | |
107 | | std::string W5 = "\";\n" |
108 | | "var algorithm = getAlgorithm("; |
109 | | |
110 | | std::string W6 = ");\n" |
111 | | "var sig = RSASign(algorithm, privateKey, dataToSign);\n" |
112 | | "RSAVerify(algorithm, publicKey, sig, dataToSign);\n"; |
113 | | |
114 | 115k | void EnvTest(v8::Isolate* isolate_, char* env_string) { |
115 | 115k | const v8::HandleScope handle_scope(isolate_); |
116 | 115k | Argv argv; |
117 | | |
118 | 115k | node::EnvironmentFlags::Flags flags = node::EnvironmentFlags::kDefaultFlags; |
119 | 115k | auto isolate = handle_scope.GetIsolate(); |
120 | 115k | v8::Local<v8::Context> context_ = node::NewContext(isolate); |
121 | 115k | context_->Enter(); |
122 | | |
123 | 115k | node::IsolateData* isolate_data_ = node::CreateIsolateData(isolate, ¤t_loop, |
124 | 115k | platform.get()); |
125 | 115k | std::vector<std::string> args(*argv, *argv + 1); |
126 | 115k | std::vector<std::string> exec_args(*argv, *argv + 1); |
127 | 115k | node::Environment* environment_ = node::CreateEnvironment(isolate_data_, |
128 | 115k | context_, args, exec_args, flags); |
129 | 115k | node::Environment* envi = environment_; |
130 | 115k | SetProcessExitHandler(envi, [&](node::Environment* env_, int exit_code) { |
131 | 3.21k | node::Stop(envi); |
132 | 3.21k | }); |
133 | 115k | node::LoadEnvironment(envi, env_string); |
134 | | |
135 | | // Cleanup! |
136 | 115k | node::FreeEnvironment(environment_); |
137 | 115k | node::FreeIsolateData(isolate_data_); |
138 | 115k | context_->Exit(); |
139 | 115k | } |
140 | | |
141 | 12.2k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) { |
142 | 12.2k | FuzzedDataProvider prov(data2, size); |
143 | 12.2k | std::string s1 = prov.ConsumeRandomLengthString(); |
144 | 12.2k | std::string s2 = prov.ConsumeRandomLengthString(); |
145 | 12.2k | std::string s3 = prov.ConsumeRandomLengthString(); |
146 | 12.2k | int alg = prov.ConsumeIntegralInRange<int>(0, 999); |
147 | 12.2k | if (hasUnescapedSingleQuotes(s1)) { |
148 | 96 | return 0; |
149 | 96 | } |
150 | 12.1k | if (hasUnescapedSingleQuotes(s2)) { |
151 | 61 | return 0; |
152 | 61 | } |
153 | 12.0k | if (hasUnescapedDoubleQuotes(s3)) { |
154 | 50 | return 0; |
155 | 50 | } |
156 | 12.0k | std::stringstream stream; |
157 | 12.0k | stream << W1 << W2 << s1 << W3 << s2 << W4 << s3 << W5 << alg << W6 << std::endl; |
158 | 12.0k | std::string js_code = stream.str(); |
159 | 12.0k | FuzzerFixtureHelper ffh; |
160 | 12.0k | EnvTest(ffh.isolate_, (char*)js_code.c_str()); |
161 | 12.0k | ffh.Teardown(); |
162 | 12.0k | return 0; |
163 | 12.0k | } |
164 | | |