Skip to content

Commit a36aa04

Browse files
committed
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 75d41cf commit a36aa04

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
@@ -4,6 +4,9 @@ const errors = require('internal/errors');
44
const util = require('util');
55
const constants = process.binding('constants').os.signals;
66

7+
const internalBinding = process._internalBinding;
8+
delete process._internalBinding;
9+
710
const assert = process.assert = function(x, msg) {
811
if (!x) throw new errors.Error('ERR_ASSERTION', msg || 'assertion error');
912
};
@@ -256,5 +259,6 @@ module.exports = {
256259
setupKillAndExit,
257260
setupSignalHandlers,
258261
setupChannel,
259-
setupRawDebug
262+
setupRawDebug,
263+
internalBinding
260264
};

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
@@ -302,6 +302,7 @@ class ModuleWrap;
302302
V(async_hooks_after_function, v8::Function) \
303303
V(async_hooks_promise_resolve_function, v8::Function) \
304304
V(binding_cache_object, v8::Object) \
305+
V(internal_binding_cache_object, v8::Object) \
305306
V(buffer_prototype_object, v8::Object) \
306307
V(context, v8::Context) \
307308
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
@@ -183,6 +183,7 @@ static bool v8_is_profiling = false;
183183
static bool node_is_initialized = false;
184184
static node_module* modpending;
185185
static node_module* modlist_builtin;
186+
static node_module* modlist_internal;
186187
static node_module* modlist_linked;
187188
static node_module* modlist_addon;
188189
static bool trace_enabled = false;
@@ -2574,6 +2575,9 @@ extern "C" void node_module_register(void* m) {
25742575
if (mp->nm_flags & NM_F_BUILTIN) {
25752576
mp->nm_link = modlist_builtin;
25762577
modlist_builtin = mp;
2578+
} else if (mp->nm_flags & NM_F_INTERNAL) {
2579+
mp->nm_link = modlist_internal;
2580+
modlist_internal = mp;
25772581
} else if (!node_is_initialized) {
25782582
// "Linked" modules are included as part of the node project.
25792583
// Like builtins they are registered *before* node::Init runs.
@@ -2585,28 +2589,28 @@ extern "C" void node_module_register(void* m) {
25852589
}
25862590
}
25872591

2588-
struct node_module* get_builtin_module(const char* name) {
2592+
inline struct node_module* FindModule(struct node_module* list,
2593+
const char* name,
2594+
int flag) {
25892595
struct node_module* mp;
25902596

2591-
for (mp = modlist_builtin; mp != nullptr; mp = mp->nm_link) {
2597+
for (mp = list; mp != nullptr; mp = mp->nm_link) {
25922598
if (strcmp(mp->nm_modname, name) == 0)
25932599
break;
25942600
}
25952601

2596-
CHECK(mp == nullptr || (mp->nm_flags & NM_F_BUILTIN) != 0);
2597-
return (mp);
2602+
CHECK(mp == nullptr || (mp->nm_flags & flag) != 0);
2603+
return mp;
25982604
}
25992605

2600-
struct node_module* get_linked_module(const char* name) {
2601-
struct node_module* mp;
2602-
2603-
for (mp = modlist_linked; mp != nullptr; mp = mp->nm_link) {
2604-
if (strcmp(mp->nm_modname, name) == 0)
2605-
break;
2606-
}
2607-
2608-
CHECK(mp == nullptr || (mp->nm_flags & NM_F_LINKED) != 0);
2609-
return mp;
2606+
node_module* get_builtin_module(const char* name) {
2607+
return FindModule(modlist_builtin, name, NM_F_BUILTIN);
2608+
}
2609+
node_module* get_internal_module(const char* name) {
2610+
return FindModule(modlist_internal, name, NM_F_INTERNAL);
2611+
}
2612+
node_module* get_linked_module(const char* name) {
2613+
return FindModule(modlist_linked, name, NM_F_LINKED);
26102614
}
26112615

26122616
struct DLib {
@@ -2880,66 +2884,119 @@ void ProcessEmitWarning(Environment* env, const char* fmt, ...) {
28802884
f.As<v8::Function>()->Call(process, 1, &arg);
28812885
}
28822886

2887+
static bool PullFromCache(Environment* env,
2888+
const FunctionCallbackInfo<Value>& args,
2889+
Local<String> module,
2890+
Local<Object> cache) {
2891+
Local<Context> context = env->context();
2892+
Local<Value> exports_v;
2893+
Local<Object> exports;
2894+
if (cache->Get(context, module).ToLocal(&exports_v) &&
2895+
exports_v->IsObject() &&
2896+
exports_v->ToObject(context).ToLocal(&exports)) {
2897+
args.GetReturnValue().Set(exports);
2898+
return true;
2899+
}
2900+
return false;
2901+
}
2902+
2903+
static Local<Object> InitModule(Environment* env,
2904+
node_module* mod,
2905+
Local<String> module) {
2906+
Local<Object> exports = Object::New(env->isolate());
2907+
// Internal bindings don't have a "module" object, only exports.
2908+
CHECK_EQ(mod->nm_register_func, nullptr);
2909+
CHECK_NE(mod->nm_context_register_func, nullptr);
2910+
Local<Value> unused = Undefined(env->isolate());
2911+
mod->nm_context_register_func(exports,
2912+
unused,
2913+
env->context(),
2914+
mod->nm_priv);
2915+
return exports;
2916+
}
2917+
2918+
static void ThrowIfNoSuchModule(Environment* env, const char* module_v) {
2919+
char errmsg[1024];
2920+
snprintf(errmsg,
2921+
sizeof(errmsg),
2922+
"No such module: %s",
2923+
module_v);
2924+
env->ThrowError(errmsg);
2925+
}
28832926

28842927
static void Binding(const FunctionCallbackInfo<Value>& args) {
28852928
Environment* env = Environment::GetCurrent(args);
28862929

2887-
Local<String> module = args[0]->ToString(env->isolate());
2888-
node::Utf8Value module_v(env->isolate(), module);
2930+
Local<String> module;
2931+
if (!args[0]->ToString(env->context()).ToLocal(&module)) return;
28892932

28902933
Local<Object> cache = env->binding_cache_object();
2891-
Local<Object> exports;
28922934

2893-
if (cache->Has(env->context(), module).FromJust()) {
2894-
exports = cache->Get(module)->ToObject(env->isolate());
2895-
args.GetReturnValue().Set(exports);
2935+
if (PullFromCache(env, args, module, cache))
28962936
return;
2897-
}
28982937

28992938
// Append a string to process.moduleLoadList
29002939
char buf[1024];
2940+
node::Utf8Value module_v(env->isolate(), module);
29012941
snprintf(buf, sizeof(buf), "Binding %s", *module_v);
29022942

29032943
Local<Array> modules = env->module_load_list_array();
29042944
uint32_t l = modules->Length();
29052945
modules->Set(l, OneByteString(env->isolate(), buf));
29062946

29072947
node_module* mod = get_builtin_module(*module_v);
2948+
Local<Object> exports;
29082949
if (mod != nullptr) {
2909-
exports = Object::New(env->isolate());
2910-
// Internal bindings don't have a "module" object, only exports.
2911-
CHECK_EQ(mod->nm_register_func, nullptr);
2912-
CHECK_NE(mod->nm_context_register_func, nullptr);
2913-
Local<Value> unused = Undefined(env->isolate());
2914-
mod->nm_context_register_func(exports, unused,
2915-
env->context(), mod->nm_priv);
2916-
cache->Set(module, exports);
2950+
exports = InitModule(env, mod, module);
29172951
} else if (!strcmp(*module_v, "constants")) {
29182952
exports = Object::New(env->isolate());
29192953
CHECK(exports->SetPrototype(env->context(),
29202954
Null(env->isolate())).FromJust());
29212955
DefineConstants(env->isolate(), exports);
2922-
cache->Set(module, exports);
29232956
} else if (!strcmp(*module_v, "natives")) {
29242957
exports = Object::New(env->isolate());
29252958
DefineJavaScript(env, exports);
2926-
cache->Set(module, exports);
29272959
} else {
2928-
char errmsg[1024];
2929-
snprintf(errmsg,
2930-
sizeof(errmsg),
2931-
"No such module: %s",
2932-
*module_v);
2933-
return env->ThrowError(errmsg);
2960+
return ThrowIfNoSuchModule(env, *module_v);
29342961
}
2962+
cache->Set(module, exports);
2963+
2964+
args.GetReturnValue().Set(exports);
2965+
}
2966+
2967+
static void InternalBinding(const FunctionCallbackInfo<Value>& args) {
2968+
Environment* env = Environment::GetCurrent(args);
2969+
2970+
Local<String> module;
2971+
if (!args[0]->ToString(env->context()).ToLocal(&module)) return;
2972+
2973+
Local<Object> cache = env->internal_binding_cache_object();
2974+
2975+
if (PullFromCache(env, args, module, cache))
2976+
return;
2977+
2978+
// Append a string to process.moduleLoadList
2979+
char buf[1024];
2980+
node::Utf8Value module_v(env->isolate(), module);
2981+
snprintf(buf, sizeof(buf), "Internal Binding %s", *module_v);
2982+
2983+
Local<Array> modules = env->module_load_list_array();
2984+
uint32_t l = modules->Length();
2985+
modules->Set(l, OneByteString(env->isolate(), buf));
2986+
2987+
node_module* mod = get_internal_module(*module_v);
2988+
if (mod == nullptr) return ThrowIfNoSuchModule(env, *module_v);
2989+
Local<Object> exports = InitModule(env, mod, module);
2990+
cache->Set(module, exports);
29352991

29362992
args.GetReturnValue().Set(exports);
29372993
}
29382994

29392995
static void LinkedBinding(const FunctionCallbackInfo<Value>& args) {
29402996
Environment* env = Environment::GetCurrent(args.GetIsolate());
29412997

2942-
Local<String> module_name = args[0]->ToString(env->isolate());
2998+
Local<String> module_name;
2999+
if (!args[0]->ToString(env->context()).ToLocal(&module_name)) return;
29433000

29443001
Local<Object> cache = env->binding_cache_object();
29453002
Local<Value> exports_v = cache->Get(module_name);
@@ -3674,6 +3731,7 @@ void SetupProcessObject(Environment* env,
36743731

36753732
env->SetMethod(process, "binding", Binding);
36763733
env->SetMethod(process, "_linkedBinding", LinkedBinding);
3734+
env->SetMethod(process, "_internalBinding", InternalBinding);
36773735

36783736
env->SetMethod(process, "_setupProcessObject", SetupProcessObject);
36793737
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
@@ -324,6 +324,9 @@ class InternalCallbackScope {
324324
bool closed_ = false;
325325
};
326326

327+
#define NODE_MODULE_CONTEXT_AWARE_INTERNAL(modname, regfunc) \
328+
NODE_MODULE_CONTEXT_AWARE_X(modname, regfunc, NULL, NM_F_INTERNAL) \
329+
327330
} // namespace node
328331

329332

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)