Skip to content

Commit 7307e1d

Browse files
bmecktargos
authored andcommitted
src: add internalBindings for binding isolation
This commit adds a method to internal/process that allows access to bindings that are not intended to be used by user code. It has a separate cache object and modlist in order to avoid collisions. You can use NODE_MODULE_CONTEXT_AWARE_INTERNAL to register a C++ module as an internal. PR-URL: #15759 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Brian White <mscdex@mscdex.net> Reviewed-By: Refael Ackermann <refack@gmail.com>
1 parent c8db023 commit 7307e1d

File tree

10 files changed

+135
-49
lines changed

10 files changed

+135
-49
lines changed

lib/internal/loader/ModuleWrap.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

3-
const { ModuleWrap } = process.binding('module_wrap');
3+
const { ModuleWrap } =
4+
require('internal/process').internalBinding('module_wrap');
45
const debug = require('util').debuglog('esm');
56
const ArrayJoin = Function.call.bind(Array.prototype.join);
67
const ArrayMap = Function.call.bind(Array.prototype.map);

lib/internal/loader/search.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const { URL } = require('url');
44
const CJSmodule = require('module');
55
const errors = require('internal/errors');
6-
const { resolve } = process.binding('module_wrap');
6+
const { resolve } = require('internal/process').internalBinding('module_wrap');
77

88
module.exports = (target, base) => {
99
if (base === undefined) {

lib/internal/process.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
const util = require('util');
44
const constants = process.binding('constants').os.signals;
55

6+
const internalBinding = process._internalBinding;
7+
delete process._internalBinding;
8+
69
const assert = process.assert = function(x, msg) {
710
if (!x) throw new Error(msg || 'assertion error');
811
};
@@ -263,5 +266,6 @@ module.exports = {
263266
setupKillAndExit,
264267
setupSignalHandlers,
265268
setupChannel,
266-
setupRawDebug
269+
setupRawDebug,
270+
internalBinding
267271
};

src/env-inl.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,17 @@ inline Environment::Environment(IsolateData* isolate_data,
303303
v8::HandleScope handle_scope(isolate());
304304
v8::Context::Scope context_scope(context);
305305
set_as_external(v8::External::New(isolate(), this));
306-
set_binding_cache_object(v8::Object::New(isolate()));
306+
307+
v8::Local<v8::Primitive> null = v8::Null(isolate());
308+
v8::Local<v8::Object> binding_cache_object = v8::Object::New(isolate());
309+
CHECK(binding_cache_object->SetPrototype(context, null).FromJust());
310+
set_binding_cache_object(binding_cache_object);
311+
312+
v8::Local<v8::Object> internal_binding_cache_object =
313+
v8::Object::New(isolate());
314+
CHECK(internal_binding_cache_object->SetPrototype(context, null).FromJust());
315+
set_internal_binding_cache_object(internal_binding_cache_object);
316+
307317
set_module_load_list_array(v8::Array::New(isolate()));
308318

309319
AssignToContext(context);

src/env.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ class ModuleWrap;
303303
V(async_hooks_after_function, v8::Function) \
304304
V(async_hooks_promise_resolve_function, v8::Function) \
305305
V(binding_cache_object, v8::Object) \
306+
V(internal_binding_cache_object, v8::Object) \
306307
V(buffer_prototype_object, v8::Object) \
307308
V(context, v8::Context) \
308309
V(domain_array, v8::Array) \

src/module_wrap.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "node_url.h"
88
#include "util.h"
99
#include "util-inl.h"
10+
#include "node_internals.h"
1011

1112
namespace node {
1213
namespace loader {
@@ -523,5 +524,5 @@ void ModuleWrap::Initialize(Local<Object> target,
523524
} // namespace loader
524525
} // namespace node
525526

526-
NODE_MODULE_CONTEXT_AWARE_BUILTIN(module_wrap,
527-
node::loader::ModuleWrap::Initialize)
527+
NODE_MODULE_CONTEXT_AWARE_INTERNAL(module_wrap,
528+
node::loader::ModuleWrap::Initialize)

src/node.cc

Lines changed: 96 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ static bool v8_is_profiling = false;
179179
static bool node_is_initialized = false;
180180
static node_module* modpending;
181181
static node_module* modlist_builtin;
182+
static node_module* modlist_internal;
182183
static node_module* modlist_linked;
183184
static node_module* modlist_addon;
184185
static bool trace_enabled = false;
@@ -2565,6 +2566,9 @@ extern "C" void node_module_register(void* m) {
25652566
if (mp->nm_flags & NM_F_BUILTIN) {
25662567
mp->nm_link = modlist_builtin;
25672568
modlist_builtin = mp;
2569+
} else if (mp->nm_flags & NM_F_INTERNAL) {
2570+
mp->nm_link = modlist_internal;
2571+
modlist_internal = mp;
25682572
} else if (!node_is_initialized) {
25692573
// "Linked" modules are included as part of the node project.
25702574
// Like builtins they are registered *before* node::Init runs.
@@ -2576,28 +2580,28 @@ extern "C" void node_module_register(void* m) {
25762580
}
25772581
}
25782582

2579-
struct node_module* get_builtin_module(const char* name) {
2583+
inline struct node_module* FindModule(struct node_module* list,
2584+
const char* name,
2585+
int flag) {
25802586
struct node_module* mp;
25812587

2582-
for (mp = modlist_builtin; mp != nullptr; mp = mp->nm_link) {
2588+
for (mp = list; mp != nullptr; mp = mp->nm_link) {
25832589
if (strcmp(mp->nm_modname, name) == 0)
25842590
break;
25852591
}
25862592

2587-
CHECK(mp == nullptr || (mp->nm_flags & NM_F_BUILTIN) != 0);
2588-
return (mp);
2593+
CHECK(mp == nullptr || (mp->nm_flags & flag) != 0);
2594+
return mp;
25892595
}
25902596

2591-
struct node_module* get_linked_module(const char* name) {
2592-
struct node_module* mp;
2593-
2594-
for (mp = modlist_linked; mp != nullptr; mp = mp->nm_link) {
2595-
if (strcmp(mp->nm_modname, name) == 0)
2596-
break;
2597-
}
2598-
2599-
CHECK(mp == nullptr || (mp->nm_flags & NM_F_LINKED) != 0);
2600-
return mp;
2597+
node_module* get_builtin_module(const char* name) {
2598+
return FindModule(modlist_builtin, name, NM_F_BUILTIN);
2599+
}
2600+
node_module* get_internal_module(const char* name) {
2601+
return FindModule(modlist_internal, name, NM_F_INTERNAL);
2602+
}
2603+
node_module* get_linked_module(const char* name) {
2604+
return FindModule(modlist_linked, name, NM_F_LINKED);
26012605
}
26022606

26032607
// DLOpen is process.dlopen(module, filename).
@@ -2822,66 +2826,119 @@ void ProcessEmitWarning(Environment* env, const char* fmt, ...) {
28222826
f.As<v8::Function>()->Call(process, 1, &arg);
28232827
}
28242828

2829+
static bool PullFromCache(Environment* env,
2830+
const FunctionCallbackInfo<Value>& args,
2831+
Local<String> module,
2832+
Local<Object> cache) {
2833+
Local<Context> context = env->context();
2834+
Local<Value> exports_v;
2835+
Local<Object> exports;
2836+
if (cache->Get(context, module).ToLocal(&exports_v) &&
2837+
exports_v->IsObject() &&
2838+
exports_v->ToObject(context).ToLocal(&exports)) {
2839+
args.GetReturnValue().Set(exports);
2840+
return true;
2841+
}
2842+
return false;
2843+
}
2844+
2845+
static Local<Object> InitModule(Environment* env,
2846+
node_module* mod,
2847+
Local<String> module) {
2848+
Local<Object> exports = Object::New(env->isolate());
2849+
// Internal bindings don't have a "module" object, only exports.
2850+
CHECK_EQ(mod->nm_register_func, nullptr);
2851+
CHECK_NE(mod->nm_context_register_func, nullptr);
2852+
Local<Value> unused = Undefined(env->isolate());
2853+
mod->nm_context_register_func(exports,
2854+
unused,
2855+
env->context(),
2856+
mod->nm_priv);
2857+
return exports;
2858+
}
2859+
2860+
static void ThrowIfNoSuchModule(Environment* env, const char* module_v) {
2861+
char errmsg[1024];
2862+
snprintf(errmsg,
2863+
sizeof(errmsg),
2864+
"No such module: %s",
2865+
module_v);
2866+
env->ThrowError(errmsg);
2867+
}
28252868

28262869
static void Binding(const FunctionCallbackInfo<Value>& args) {
28272870
Environment* env = Environment::GetCurrent(args);
28282871

2829-
Local<String> module = args[0]->ToString(env->isolate());
2830-
node::Utf8Value module_v(env->isolate(), module);
2872+
Local<String> module;
2873+
if (!args[0]->ToString(env->context()).ToLocal(&module)) return;
28312874

28322875
Local<Object> cache = env->binding_cache_object();
2833-
Local<Object> exports;
28342876

2835-
if (cache->Has(env->context(), module).FromJust()) {
2836-
exports = cache->Get(module)->ToObject(env->isolate());
2837-
args.GetReturnValue().Set(exports);
2877+
if (PullFromCache(env, args, module, cache))
28382878
return;
2839-
}
28402879

28412880
// Append a string to process.moduleLoadList
28422881
char buf[1024];
2882+
node::Utf8Value module_v(env->isolate(), module);
28432883
snprintf(buf, sizeof(buf), "Binding %s", *module_v);
28442884

28452885
Local<Array> modules = env->module_load_list_array();
28462886
uint32_t l = modules->Length();
28472887
modules->Set(l, OneByteString(env->isolate(), buf));
28482888

28492889
node_module* mod = get_builtin_module(*module_v);
2890+
Local<Object> exports;
28502891
if (mod != nullptr) {
2851-
exports = Object::New(env->isolate());
2852-
// Internal bindings don't have a "module" object, only exports.
2853-
CHECK_EQ(mod->nm_register_func, nullptr);
2854-
CHECK_NE(mod->nm_context_register_func, nullptr);
2855-
Local<Value> unused = Undefined(env->isolate());
2856-
mod->nm_context_register_func(exports, unused,
2857-
env->context(), mod->nm_priv);
2858-
cache->Set(module, exports);
2892+
exports = InitModule(env, mod, module);
28592893
} else if (!strcmp(*module_v, "constants")) {
28602894
exports = Object::New(env->isolate());
28612895
CHECK(exports->SetPrototype(env->context(),
28622896
Null(env->isolate())).FromJust());
28632897
DefineConstants(env->isolate(), exports);
2864-
cache->Set(module, exports);
28652898
} else if (!strcmp(*module_v, "natives")) {
28662899
exports = Object::New(env->isolate());
28672900
DefineJavaScript(env, exports);
2868-
cache->Set(module, exports);
28692901
} else {
2870-
char errmsg[1024];
2871-
snprintf(errmsg,
2872-
sizeof(errmsg),
2873-
"No such module: %s",
2874-
*module_v);
2875-
return env->ThrowError(errmsg);
2902+
return ThrowIfNoSuchModule(env, *module_v);
28762903
}
2904+
cache->Set(module, exports);
2905+
2906+
args.GetReturnValue().Set(exports);
2907+
}
2908+
2909+
static void InternalBinding(const FunctionCallbackInfo<Value>& args) {
2910+
Environment* env = Environment::GetCurrent(args);
2911+
2912+
Local<String> module;
2913+
if (!args[0]->ToString(env->context()).ToLocal(&module)) return;
2914+
2915+
Local<Object> cache = env->internal_binding_cache_object();
2916+
2917+
if (PullFromCache(env, args, module, cache))
2918+
return;
2919+
2920+
// Append a string to process.moduleLoadList
2921+
char buf[1024];
2922+
node::Utf8Value module_v(env->isolate(), module);
2923+
snprintf(buf, sizeof(buf), "Internal Binding %s", *module_v);
2924+
2925+
Local<Array> modules = env->module_load_list_array();
2926+
uint32_t l = modules->Length();
2927+
modules->Set(l, OneByteString(env->isolate(), buf));
2928+
2929+
node_module* mod = get_internal_module(*module_v);
2930+
if (mod == nullptr) return ThrowIfNoSuchModule(env, *module_v);
2931+
Local<Object> exports = InitModule(env, mod, module);
2932+
cache->Set(module, exports);
28772933

28782934
args.GetReturnValue().Set(exports);
28792935
}
28802936

28812937
static void LinkedBinding(const FunctionCallbackInfo<Value>& args) {
28822938
Environment* env = Environment::GetCurrent(args.GetIsolate());
28832939

2884-
Local<String> module_name = args[0]->ToString(env->isolate());
2940+
Local<String> module_name;
2941+
if (!args[0]->ToString(env->context()).ToLocal(&module_name)) return;
28852942

28862943
Local<Object> cache = env->binding_cache_object();
28872944
Local<Value> exports_v = cache->Get(module_name);
@@ -3616,6 +3673,7 @@ void SetupProcessObject(Environment* env,
36163673

36173674
env->SetMethod(process, "binding", Binding);
36183675
env->SetMethod(process, "_linkedBinding", LinkedBinding);
3676+
env->SetMethod(process, "_internalBinding", InternalBinding);
36193677

36203678
env->SetMethod(process, "_setupProcessObject", SetupProcessObject);
36213679
env->SetMethod(process, "_setupNextTick", SetupNextTick);

src/node.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,9 @@ typedef void (*addon_context_register_func)(
421421
v8::Local<v8::Context> context,
422422
void* priv);
423423

424-
#define NM_F_BUILTIN 0x01
425-
#define NM_F_LINKED 0x02
424+
#define NM_F_BUILTIN 0x01
425+
#define NM_F_LINKED 0x02
426+
#define NM_F_INTERNAL 0x04
426427

427428
struct node_module {
428429
int nm_version;
@@ -436,9 +437,6 @@ struct node_module {
436437
struct node_module* nm_link;
437438
};
438439

439-
node_module* get_builtin_module(const char *name);
440-
node_module* get_linked_module(const char *name);
441-
442440
extern "C" NODE_EXTERN void node_module_register(void* mod);
443441

444442
#ifdef _WIN32

src/node_internals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ class InternalCallbackScope {
301301
bool closed_ = false;
302302
};
303303

304+
#define NODE_MODULE_CONTEXT_AWARE_INTERNAL(modname, regfunc) \
305+
NODE_MODULE_CONTEXT_AWARE_X(modname, regfunc, NULL, NM_F_INTERNAL) \
306+
304307
} // namespace node
305308

306309

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
6+
assert.strictEqual(undefined, process._internalBinding);
7+
assert.strictEqual(undefined, process.internalBinding);
8+
assert.throws(() => {
9+
process.binding('module_wrap');
10+
}, /No such module/);

0 commit comments

Comments
 (0)