Skip to content

Commit 09443c3

Browse files
committed
[WIP] src: introduce Policy permissions
1 parent 7faeddf commit 09443c3

18 files changed

Lines changed: 693 additions & 13 deletions

lib/internal/bootstrap/loaders.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141

4242
// This file is compiled as if it's wrapped in a function with arguments
4343
// passed by node::RunBootstrapping()
44-
/* global process, getLinkedBinding, getInternalBinding, primordials */
44+
/* global process, getLinkedBinding, getInternalBinding, primordials,
45+
runInPrivilegedScope */
4546

4647
const {
4748
ArrayPrototypeMap,
@@ -280,7 +281,13 @@ class NativeModule {
280281
requireWithFallbackInDeps : nativeModuleRequire;
281282

282283
const fn = compileFunction(id);
283-
fn(this.exports, requireFn, this, process, internalBinding, primordials);
284+
fn(this.exports,
285+
requireFn,
286+
this,
287+
process,
288+
internalBinding,
289+
primordials,
290+
runInPrivilegedScope);
284291

285292
this.loaded = true;
286293
} finally {

lib/internal/bootstrap/node.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@
3333
'use strict';
3434

3535
// This file is compiled as if it's wrapped in a function with arguments
36-
// passed by node::RunBootstrapping()
37-
/* global process, require, internalBinding, primordials */
36+
// passed by node::RunBootstrapping():
37+
// global process, require, internalBinding, primordials,
38+
// runInPriviledgedScope
3839

3940
setupPrepareStackTrace();
4041

lib/internal/bootstrap/pre_execution.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ function initializeClusterIPC() {
356356

357357
function initializePolicy() {
358358
const experimentalPolicy = getOptionValue('--experimental-policy');
359+
const { setup, check, deny } = require('internal/process/policy');
359360
if (experimentalPolicy) {
360361
process.emitWarning('Policies are experimental.',
361362
'ExperimentalWarning');
@@ -398,9 +399,16 @@ function initializePolicy() {
398399
throw new ERR_MANIFEST_ASSERT_INTEGRITY(manifestURL, realIntegrities);
399400
}
400401
}
401-
require('internal/process/policy')
402-
.setup(src, manifestURL.href);
402+
setup(src, manifestURL.href);
403403
}
404+
ObjectDefineProperty(process, 'policy', {
405+
enumerable: true,
406+
configurable: false,
407+
value: {
408+
deny,
409+
check,
410+
}
411+
});
404412
}
405413

406414
function initializeWASI() {

lib/internal/process/policy.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ const {
88

99
const {
1010
ERR_MANIFEST_TDZ,
11+
ERR_INVALID_ARG_TYPE,
12+
ERR_INVALID_ARG_VALUE,
1113
} = require('internal/errors').codes;
14+
15+
const policy = internalBinding('policy');
16+
1217
const { Manifest } = require('internal/policy/manifest');
1318
let manifest;
1419
let manifestSrc;
@@ -57,5 +62,29 @@ module.exports = ObjectFreeze({
5762

5863
assertIntegrity(moduleURL, content) {
5964
this.manifest.assertIntegrity(moduleURL, content);
65+
},
66+
67+
deny(permissions) {
68+
if (typeof permissions !== 'string')
69+
throw new ERR_INVALID_ARG_TYPE('permissions', 'string', permissions);
70+
const ret = policy.deny(permissions);
71+
if (typeof ret === 'number')
72+
throw new ERR_INVALID_ARG_VALUE('permissions', permissions);
73+
},
74+
75+
fastCheck(permission) {
76+
// This should only be used by internal code. Skips explicit
77+
// type checking to improve performance. The permission
78+
// argument must be a Int32
79+
return policy.fastCheck(permission);
80+
},
81+
82+
check(permissions) {
83+
if (typeof permissions !== 'string')
84+
throw new ERR_INVALID_ARG_TYPE('permission', 'string', permissions);
85+
const ret = policy.check(permissions);
86+
if (typeof ret === 'number')
87+
throw new ERR_INVALID_ARG_VALUE('permissions', permissions);
88+
return ret;
6089
}
6190
});

node.gyp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@
660660
'src/stream_wrap.cc',
661661
'src/string_bytes.cc',
662662
'src/string_decoder.cc',
663+
'src/policy/policy.cc',
663664
'src/tcp_wrap.cc',
664665
'src/timers.cc',
665666
'src/timer_wrap.cc',
@@ -735,6 +736,8 @@
735736
'src/node_perf.h',
736737
'src/node_perf_common.h',
737738
'src/node_platform.h',
739+
'src/policy/policy.h',
740+
'src/policy/policy-inl.h',
738741
'src/node_process.h',
739742
'src/node_report.h',
740743
'src/node_revert.h',

src/env-inl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "env.h"
3030
#include "node.h"
3131
#include "util-inl.h"
32+
#include "policy/policy-inl.h"
3233
#include "uv.h"
3334
#include "v8.h"
3435
#include "node_perf_common.h"
@@ -246,6 +247,10 @@ inline size_t Environment::async_callback_scope_depth() const {
246247
return async_callback_scope_depth_;
247248
}
248249

250+
policy::PrivilegedAccessContext* Environment::privileged_access_context() {
251+
return &privileged_access_context_;
252+
}
253+
249254
inline void Environment::PushAsyncCallbackScope() {
250255
async_callback_scope_depth_++;
251256
}

src/env.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ Environment::Environment(IsolateData* isolate_data,
313313
ThreadId thread_id)
314314
: isolate_(isolate),
315315
isolate_data_(isolate_data),
316+
privileged_access_context_(isolate_data->options()->per_env.get()),
316317
async_hooks_(isolate, MAYBE_FIELD_PTR(env_info, async_hooks)),
317318
immediate_info_(isolate, MAYBE_FIELD_PTR(env_info, immediate_info)),
318319
tick_info_(isolate, MAYBE_FIELD_PTR(env_info, tick_info)),

src/env.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "node_main_instance.h"
3838
#include "node_options.h"
3939
#include "node_perf_common.h"
40+
#include "policy/policy.h"
4041
#include "req_wrap.h"
4142
#include "util.h"
4243
#include "uv.h"
@@ -375,6 +376,7 @@ constexpr size_t kFsStatsBufferLength =
375376
V(replacement_string, "replacement") \
376377
V(require_string, "require") \
377378
V(retry_string, "retry") \
379+
V(run_in_privileged_scope_string, "runInPrivilegedScope") \
378380
V(scheme_string, "scheme") \
379381
V(scopeid_string, "scopeid") \
380382
V(serial_number_string, "serialNumber") \
@@ -547,6 +549,7 @@ constexpr size_t kFsStatsBufferLength =
547549
V(primordials, v8::Object) \
548550
V(promise_hook_handler, v8::Function) \
549551
V(promise_reject_callback, v8::Function) \
552+
V(run_in_privileged_scope, v8::Function) \
550553
V(script_data_constructor_function, v8::Function) \
551554
V(source_map_cache_getter, v8::Function) \
552555
V(tick_callback_function, v8::Function) \
@@ -977,6 +980,7 @@ class Environment : public MemoryRetainer {
977980
v8::MaybeLocal<v8::Value> BootstrapInternalLoaders();
978981
v8::MaybeLocal<v8::Value> BootstrapNode();
979982
v8::MaybeLocal<v8::Value> RunBootstrapping();
983+
bool BootstrapPrivilegedAccessContext();
980984

981985
inline size_t async_callback_scope_depth() const;
982986
inline void PushAsyncCallbackScope();
@@ -1036,6 +1040,8 @@ class Environment : public MemoryRetainer {
10361040
inline const std::vector<std::string>& argv();
10371041
const std::string& exec_path() const;
10381042

1043+
inline policy::PrivilegedAccessContext* privileged_access_context();
1044+
10391045
typedef void (*HandleCleanupCb)(Environment* env,
10401046
uv_handle_t* handle,
10411047
void* arg);
@@ -1397,6 +1403,7 @@ class Environment : public MemoryRetainer {
13971403
std::list<binding::DLib> loaded_addons_;
13981404
v8::Isolate* const isolate_;
13991405
IsolateData* const isolate_data_;
1406+
policy::PrivilegedAccessContext privileged_access_context_;
14001407
uv_timer_t timer_handle_;
14011408
uv_check_t immediate_check_handle_;
14021409
uv_idle_t immediate_idle_handle_;

src/node.cc

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "node_revert.h"
4040
#include "node_v8_platform-inl.h"
4141
#include "node_version.h"
42+
#include "policy/policy.h"
4243

4344
#if HAVE_OPENSSL
4445
#include "allocated_buffer-inl.h" // Inlined functions needed by node_crypto.h
@@ -294,6 +295,18 @@ void Environment::InitializeDiagnostics() {
294295
#endif
295296
}
296297

298+
bool Environment::BootstrapPrivilegedAccessContext() {
299+
Local<Function> run_in_privileged_scope;
300+
MaybeLocal<Function> maybe_run_in_privileged_scope =
301+
Function::New(
302+
context(),
303+
policy::PrivilegedAccessContext::Run);
304+
if (!maybe_run_in_privileged_scope.ToLocal(&run_in_privileged_scope))
305+
return false;
306+
set_run_in_privileged_scope(run_in_privileged_scope);
307+
return true;
308+
}
309+
297310
MaybeLocal<Value> Environment::BootstrapInternalLoaders() {
298311
EscapableHandleScope scope(isolate_);
299312

@@ -302,7 +315,8 @@ MaybeLocal<Value> Environment::BootstrapInternalLoaders() {
302315
process_string(),
303316
FIXED_ONE_BYTE_STRING(isolate_, "getLinkedBinding"),
304317
FIXED_ONE_BYTE_STRING(isolate_, "getInternalBinding"),
305-
primordials_string()};
318+
primordials_string(),
319+
run_in_privileged_scope_string()};
306320
std::vector<Local<Value>> loaders_args = {
307321
process_object(),
308322
NewFunctionTemplate(binding::GetLinkedBinding)
@@ -311,7 +325,8 @@ MaybeLocal<Value> Environment::BootstrapInternalLoaders() {
311325
NewFunctionTemplate(binding::GetInternalBinding)
312326
->GetFunction(context())
313327
.ToLocalChecked(),
314-
primordials()};
328+
primordials(),
329+
run_in_privileged_scope()};
315330

316331
// Bootstrap internal loaders
317332
Local<Value> loader_exports;
@@ -348,12 +363,14 @@ MaybeLocal<Value> Environment::BootstrapNode() {
348363
process_string(),
349364
require_string(),
350365
internal_binding_string(),
351-
primordials_string()};
366+
primordials_string(),
367+
run_in_privileged_scope_string()};
352368
std::vector<Local<Value>> node_args = {
353369
process_object(),
354370
native_module_require(),
355371
internal_binding_loader(),
356-
primordials()};
372+
primordials(),
373+
run_in_privileged_scope()};
357374

358375
MaybeLocal<Value> result = ExecuteBootstrapper(
359376
this, "internal/bootstrap/node", &node_params, &node_args);
@@ -399,6 +416,10 @@ MaybeLocal<Value> Environment::RunBootstrapping() {
399416

400417
CHECK(!has_run_bootstrapping_code());
401418

419+
if (!BootstrapPrivilegedAccessContext()) {
420+
return MaybeLocal<Value>();
421+
}
422+
402423
if (BootstrapInternalLoaders().IsEmpty()) {
403424
return MaybeLocal<Value>();
404425
}
@@ -436,7 +457,8 @@ MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
436457
env->require_string(),
437458
env->internal_binding_string(),
438459
env->primordials_string(),
439-
FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
460+
FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete"),
461+
env->run_in_privileged_scope_string()};
440462

441463
std::vector<Local<Value>> arguments = {
442464
env->process_object(),
@@ -445,7 +467,8 @@ MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
445467
env->primordials(),
446468
env->NewFunctionTemplate(MarkBootstrapComplete)
447469
->GetFunction(env->context())
448-
.ToLocalChecked()};
470+
.ToLocalChecked(),
471+
env->run_in_privileged_scope()};
449472

450473
return scope.EscapeMaybe(
451474
ExecuteBootstrapper(env, main_script_id, &parameters, &arguments));

src/node_binding.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
V(os) \
7070
V(performance) \
7171
V(pipe_wrap) \
72+
V(policy) \
7273
V(process_wrap) \
7374
V(process_methods) \
7475
V(report) \

0 commit comments

Comments
 (0)