Skip to content

Commit

Permalink
src: add policy check and deny base functions
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelGSS committed Jul 27, 2022
1 parent d7f1934 commit 1a6d460
Show file tree
Hide file tree
Showing 20 changed files with 429 additions and 2 deletions.
12 changes: 10 additions & 2 deletions lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ function initializeClusterIPC() {

function initializePolicy() {
const experimentalPolicy = getOptionValue('--experimental-policy');
const { setup, check, deny } = require('internal/process/policy')
if (experimentalPolicy) {
process.emitWarning('Policies are experimental.',
'ExperimentalWarning');
Expand Down Expand Up @@ -494,9 +495,16 @@ function initializePolicy() {
throw new ERR_MANIFEST_ASSERT_INTEGRITY(manifestURL, realIntegrities);
}
}
require('internal/process/policy')
.setup(src, manifestURL.href);
setup(src, manifestURL.href);
}
ObjectDefineProperty(process, 'policy', {
enumerable: true,
configurable: false,
value: {
deny,
check,
}
});
}

function initializeWASI() {
Expand Down
16 changes: 16 additions & 0 deletions lib/internal/process/policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ const {
ReflectSetPrototypeOf,
} = primordials;

const policy = internalBinding('policy');

const {
ERR_MANIFEST_TDZ,
ERR_INVALID_ARG_TYPE,
} = require('internal/errors').codes;
const { Manifest } = require('internal/policy/manifest');
let manifest;
Expand Down Expand Up @@ -57,5 +60,18 @@ module.exports = ObjectFreeze({

assertIntegrity(moduleURL, content) {
this.manifest.assertIntegrity(moduleURL, content);
},

deny(permission) {
if (typeof permission !== 'string')
throw new ERR_INVALID_ARG_TYPE('permission', 'string', permission);
return policy.deny(permission);
},

check(permission) {
if (typeof permission !== 'string')
throw new ERR_INVALID_ARG_TYPE('permission', 'string', permission);

return policy.check(permission);
}
});
7 changes: 7 additions & 0 deletions lib/internal/repl/history.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ function setupHistory(repl, historyPath, ready) {
return ready(null, repl);
}

// TODO: make it more granular (fs.in os.homedir())
if (!process.policy.check('fs.in') || !process.policy.check('fs.out')) {
_writeToOutput(repl, '\nAccess to FileSystemIn/Out is restricted.\n' +
'REPL session history will not be persisted.\n');
return ready(null, repl);
}

if (!historyPath) {
try {
historyPath = path.join(os.homedir(), '.node_repl_history');
Expand Down
2 changes: 2 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@
'src/stream_wrap.cc',
'src/string_bytes.cc',
'src/string_decoder.cc',
'src/policy/policy.cc',
'src/tcp_wrap.cc',
'src/timers.cc',
'src/timer_wrap.cc',
Expand Down Expand Up @@ -635,6 +636,7 @@
'src/node_watchdog.h',
'src/node_worker.h',
'src/pipe_wrap.h',
'src/policy/policy.h',
'src/req_wrap.h',
'src/req_wrap-inl.h',
'src/spawn_sync.h',
Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ class NoArrayBufferZeroFillScope {
V(password_string, "password") \
V(path_string, "path") \
V(pending_handle_string, "pendingHandle") \
V(permission_string, "permission") \
V(pid_string, "pid") \
V(ping_rtt_string, "pingRTT") \
V(pipe_source_string, "pipeSource") \
Expand Down
2 changes: 2 additions & 0 deletions src/fs_event_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "node.h"
#include "node_external_reference.h"
#include "string_bytes.h"
#include "policy/policy.h"

namespace node {

Expand Down Expand Up @@ -134,6 +135,7 @@ void FSEventWrap::New(const FunctionCallbackInfo<Value>& args) {
// wrap.start(filename, persistent, recursive, encoding)
void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);

FSEventWrap* wrap = Unwrap<FSEventWrap>(args.This());
CHECK_NOT_NULL(wrap);
Expand Down
8 changes: 8 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "node_snapshot_builder.h"
#include "node_v8_platform-inl.h"
#include "node_version.h"
#include "policy/policy.h"

#if HAVE_OPENSSL
#include "node_crypto.h"
Expand Down Expand Up @@ -857,6 +858,13 @@ int ProcessGlobalArgs(std::vector<std::string>* args,

if (v8_args_as_char_ptr.size() > 1) return 9;

if (policy::root_policy.Apply(
per_process::cli_options->policy_deny).IsNothing()) {
errors->emplace_back(
"invalid permissions passed to --policy-deny");
return 12;
}

return 0;
}

Expand Down
1 change: 1 addition & 0 deletions src/node_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
V(os) \
V(performance) \
V(pipe_wrap) \
V(policy) \
V(process_wrap) \
V(process_methods) \
V(report) \
Expand Down
2 changes: 2 additions & 0 deletions src/node_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void OnFatalError(const char* location, const char* message);
// a `Local<Value>` containing the TypeError with proper code and message

#define ERRORS_WITH_CODE(V) \
V(ERR_ACCESS_DENIED, Error) \
V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, Error) \
V(ERR_BUFFER_OUT_OF_BOUNDS, RangeError) \
V(ERR_BUFFER_TOO_LARGE, Error) \
Expand Down Expand Up @@ -121,6 +122,7 @@ ERRORS_WITH_CODE(V)
// Errors with predefined static messages

#define PREDEFINED_ERROR_MESSAGES(V) \
V(ERR_ACCESS_DENIED, "Access to this API has been restricted") \
V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, \
"Buffer is not available for the current Context") \
V(ERR_CLOSED_MESSAGE_PORT, "Cannot send data on closed MessagePort") \
Expand Down
1 change: 1 addition & 0 deletions src/node_external_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class ExternalReferenceRegistry {
V(options) \
V(os) \
V(performance) \
V(policy) \
V(process_methods) \
V(process_object) \
V(report) \
Expand Down
17 changes: 17 additions & 0 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "node_process-inl.h"
#include "node_stat_watcher.h"
#include "util-inl.h"
#include "policy/policy.h"

#include "tracing/trace_event.h"

Expand Down Expand Up @@ -434,6 +435,9 @@ FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
int FileHandle::ReadStart() {
if (!IsAlive() || IsClosing())
return UV_EOF;
if (!node::policy::root_policy.is_granted(
node::policy::Permission::kFileSystemIn))
return UV_EPERM;

reading_ = true;

Expand Down Expand Up @@ -858,6 +862,8 @@ void AfterScanDirWithTypes(uv_fs_t* req) {

void Access(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);

Isolate* isolate = env->isolate();
HandleScope scope(isolate);

Expand Down Expand Up @@ -911,6 +917,7 @@ void Close(const FunctionCallbackInfo<Value>& args) {
// Used to speed up module loading. Returns an array [string, boolean]
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);
Isolate* isolate = env->isolate();
uv_loop_t* loop = env->event_loop();

Expand Down Expand Up @@ -1009,6 +1016,7 @@ static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
// The speedup comes from not creating thousands of Stat and Error objects.
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);

CHECK(args[0]->IsString());
node::Utf8Value path(env->isolate(), args[0]);
Expand All @@ -1027,6 +1035,7 @@ static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
static void Stat(const FunctionCallbackInfo<Value>& args) {
BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);

const int argc = args.Length();
CHECK_GE(argc, 2);
Expand Down Expand Up @@ -1058,6 +1067,7 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
static void LStat(const FunctionCallbackInfo<Value>& args) {
BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);

const int argc = args.Length();
CHECK_GE(argc, 3);
Expand Down Expand Up @@ -1090,6 +1100,7 @@ static void LStat(const FunctionCallbackInfo<Value>& args) {
static void FStat(const FunctionCallbackInfo<Value>& args) {
BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);

const int argc = args.Length();
CHECK_GE(argc, 2);
Expand Down Expand Up @@ -1176,6 +1187,7 @@ static void Link(const FunctionCallbackInfo<Value>& args) {

static void ReadLink(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);
Isolate* isolate = env->isolate();

const int argc = args.Length();
Expand Down Expand Up @@ -1592,6 +1604,7 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {

static void RealPath(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);
Isolate* isolate = env->isolate();

const int argc = args.Length();
Expand Down Expand Up @@ -1636,6 +1649,7 @@ static void RealPath(const FunctionCallbackInfo<Value>& args) {

static void ReadDir(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);
Isolate* isolate = env->isolate();

const int argc = args.Length();
Expand Down Expand Up @@ -1723,6 +1737,7 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) {

static void Open(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);

const int argc = args.Length();
CHECK_GE(argc, 3);
Expand Down Expand Up @@ -1756,6 +1771,7 @@ static void Open(const FunctionCallbackInfo<Value>& args) {
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
Environment* env = binding_data->env();
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);
Isolate* isolate = env->isolate();

const int argc = args.Length();
Expand Down Expand Up @@ -2035,6 +2051,7 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
*/
static void Read(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_IF_INSUFFICIENT_PERMISSIONS(env, policy::Permission::kFileSystemIn);

const int argc = args.Length();
CHECK_GE(argc, 5);
Expand Down
4 changes: 4 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,10 @@ PerProcessOptionsParser::PerProcessOptionsParser(
"force FIPS crypto (cannot be disabled)",
&PerProcessOptions::force_fips_crypto,
kAllowedInEnvironment);
AddOption("--policy-deny",
"denied permissions",
&PerProcessOptions::policy_deny,
kAllowedInEnvironment);
AddOption("--secure-heap",
"total size of the OpenSSL secure heap",
&PerProcessOptions::secure_heap,
Expand Down
2 changes: 2 additions & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ class PerProcessOptions : public Options {
bool print_v8_help = false;
bool print_version = false;

std::string policy_deny;

#ifdef NODE_HAVE_I18N_SUPPORT
std::string icu_data_dir;
#endif
Expand Down
Loading

0 comments on commit 1a6d460

Please sign in to comment.