Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,10 @@ inline bool Environment::no_browser_globals() const {
#endif
}

inline bool Environment::no_addon_permission_for_linked_bindings() const {
return flags_ & EnvironmentFlags::kNoAddonPermissionForLinkedBindings;
}

void Environment::set_source_maps_enabled(bool on) {
source_maps_enabled_ = on;
}
Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ class Environment final : public MemoryRetainer {
inline bool no_global_search_paths() const;
inline bool should_start_debug_signal_handler() const;
inline bool no_browser_globals() const;
inline bool no_addon_permission_for_linked_bindings() const;
inline uint64_t thread_id() const;
inline std::string_view thread_name() const;
inline worker::Worker* worker_context() const;
Expand Down
7 changes: 6 additions & 1 deletion src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,12 @@ enum Flags : uint64_t {
// Controls whether the InspectorAgent created for this Environment waits for
// Inspector frontend events during the Environment creation. It's used to
// call node::Stop(env) on a Worker thread that is waiting for the events.
kNoWaitForInspectorFrontend = 1 << 11
kNoWaitForInspectorFrontend = 1 << 11,
// Set this flag to exempt process._linkedBinding() from the permission
// model's addon scope (--allow-addons): linked bindings are compiled into
// the executable by the embedder, unlike addons loaded from the file system
// through process.dlopen(), which stays gated. Inherited by worker threads.
kNoAddonPermissionForLinkedBindings = 1 << 12
};
} // namespace EnvironmentFlags

Expand Down
6 changes: 4 additions & 2 deletions src/node_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1024,8 +1024,10 @@ void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {

node::Utf8Value module_name_v(env->isolate(), module_name);
const char* name = *module_name_v;
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kAddon, module_name_v.ToStringView());
if (!env->no_addon_permission_for_linked_bindings()) {
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kAddon, module_name_v.ToStringView());
}

node_module* mod = nullptr;

Expand Down
4 changes: 4 additions & 0 deletions src/node_worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,10 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
worker->environment_flags_ |= EnvironmentFlags::kNoGlobalSearchPaths;
if (env->no_browser_globals())
worker->environment_flags_ |= EnvironmentFlags::kNoBrowserGlobals;
if (env->no_addon_permission_for_linked_bindings()) {
worker->environment_flags_ |=
EnvironmentFlags::kNoAddonPermissionForLinkedBindings;
}
}

void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
Expand Down
48 changes: 48 additions & 0 deletions test/cctest/test_linked_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "node_api.h"
#include "node_test_fixture.h"

#include <string>

void InitializeBinding(v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context,
Expand Down Expand Up @@ -46,6 +48,52 @@ TEST_F(LinkedBindingTest, SimpleTest) {
CHECK_EQ(strcmp(*utf8val, "value"), 0);
}

static std::string RunScript(v8::Isolate* isolate, const char* source) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Script> script =
v8::Script::Compile(context,
v8::String::NewFromOneByte(
isolate, reinterpret_cast<const uint8_t*>(source))
.ToLocalChecked())
.ToLocalChecked();
v8::Local<v8::Value> completion_value = script->Run(context).ToLocalChecked();
v8::String::Utf8Value utf8val(isolate, completion_value);
CHECK_NOT_NULL(*utf8val);
return *utf8val;
}

TEST_F(LinkedBindingTest, PermissionModelDeniesLinkedBindingTest) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
isolate_data_->options()->per_env->permission = true;
Env test_env{handle_scope, argv};

const char* run_script =
"try { process._linkedBinding('cctest_linkedbinding').key; }"
" catch (err) { err.code; }";
CHECK_EQ(RunScript(isolate_, run_script), "ERR_ACCESS_DENIED");
}

TEST_F(LinkedBindingTest, NoAddonPermissionForLinkedBindingsTest) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
isolate_data_->options()->per_env->permission = true;
Env test_env{
handle_scope,
argv,
static_cast<node::EnvironmentFlags::Flags>(
node::EnvironmentFlags::kDefaultFlags |
node::EnvironmentFlags::kNoAddonPermissionForLinkedBindings)};

const char* linked_script =
"process._linkedBinding('cctest_linkedbinding').key";
CHECK_EQ(RunScript(isolate_, linked_script), "value");
const char* dlopen_script =
"try { process.dlopen({ exports: {} }, 'addon.node'); }"
" catch (err) { err.code; }";
CHECK_EQ(RunScript(isolate_, dlopen_script), "ERR_DLOPEN_DISABLED");
}

void InitializeLocalBinding(v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context,
Expand Down
Loading