Coverage Report

Created: 2025-07-04 09:33

/src/node/test/fuzzers/fuzz_httpparser1.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(&current_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(), &current_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 S1 =
77
  "const { HTTPParser } = require('_http_common');\n"
78
  "const { REQUEST, RESPONSE } = HTTPParser;\n"
79
  "\n"
80
  "const kOnHeaders = HTTPParser.kOnHeaders | 0;\n"
81
  "const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;\n"
82
  "const kOnBody = HTTPParser.kOnBody | 0;\n"
83
  "const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;\n"
84
  "\n"
85
  "function newParser(type) {\n"
86
  "  const parser = new HTTPParser();\n"
87
  "  parser.initialize(type, {});\n"
88
  "\n"
89
  "  parser.headers = [];\n"
90
  "  parser.url = '';\n"
91
  "\n"
92
  "  parser[kOnHeaders] = function(headers, url) {\n"
93
  "    parser.headers = parser.headers.concat(headers);\n"
94
  "    parser.url += url;\n"
95
  "  };\n"
96
  "\n"
97
  "  parser[kOnHeadersComplete] = function() {\n"
98
  "  };\n"
99
  "\n"
100
  "  parser[kOnBody] = function() {\n"
101
  "  };\n"
102
  "\n"
103
  "  parser[kOnMessageComplete] = function() {\n"
104
  "  };\n"
105
  "\n"
106
  "  return parser;\n"
107
  "}\n"
108
  "\n"
109
  "const request = Buffer.from(\"";
110
111
// RANDOM
112
113
std::string S2 =
114
  "\", 'utf-8');\n"
115
  "\n"
116
  "const onBody = (buf) => {\n"
117
  "  const body = String(buf);\n"
118
  "};\n"
119
  "const parser = newParser(REQUEST);\n"
120
  "parser.execute(request, 0, request.length);\n";
121
122
115k
void EnvTest(v8::Isolate* isolate_, char* env_string) {
123
115k
  const v8::HandleScope handle_scope(isolate_);
124
115k
  Argv argv;
125
126
115k
  node::EnvironmentFlags::Flags flags = node::EnvironmentFlags::kDefaultFlags;
127
115k
  auto isolate = handle_scope.GetIsolate();
128
115k
  v8::Local<v8::Context> context_ = node::NewContext(isolate);
129
115k
  context_->Enter();
130
131
115k
  node::IsolateData* isolate_data_ = node::CreateIsolateData(isolate, &current_loop,
132
115k
                                                             platform.get());
133
115k
  std::vector<std::string> args(*argv, *argv + 1);
134
115k
  std::vector<std::string> exec_args(*argv, *argv + 1);
135
115k
  node::Environment* environment_ = node::CreateEnvironment(isolate_data_,
136
115k
                                          context_, args, exec_args, flags);
137
115k
  node::Environment* envi = environment_;
138
115k
  SetProcessExitHandler(envi, [&](node::Environment* env_, int exit_code) {
139
2.09k
    node::Stop(envi);
140
2.09k
  });
141
115k
  node::LoadEnvironment(envi, env_string);
142
143
  // Cleanup!
144
115k
  node::FreeEnvironment(environment_);
145
115k
  node::FreeIsolateData(isolate_data_);
146
115k
  context_->Exit();
147
115k
}
148
149
66.7k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) {
150
66.7k
  FuzzedDataProvider prov(data2, size);
151
66.7k
  std::string r1 = prov.ConsumeRemainingBytesAsString();
152
66.7k
  if (hasUnescapedDoubleQuotes(r1)) {
153
243
    return 0;
154
243
  }
155
66.4k
  std::stringstream stream;
156
66.4k
  stream << S1 << r1 << S2 << std::endl;
157
66.4k
  std::string js_code = stream.str();
158
66.4k
  FuzzerFixtureHelper ffh;
159
66.4k
  EnvTest(ffh.isolate_, (char*)js_code.c_str());
160
66.4k
  ffh.Teardown();
161
66.4k
  return 0;
162
66.7k
}
163