Skip to content

Commit

Permalink
feat: add policy_deny_fs with granularity level
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelGSS committed Jul 27, 2022
1 parent 1a6d460 commit 5e7b005
Show file tree
Hide file tree
Showing 23 changed files with 1,032 additions and 179 deletions.
2 changes: 1 addition & 1 deletion lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ function initializeClusterIPC() {

function initializePolicy() {
const experimentalPolicy = getOptionValue('--experimental-policy');
const { setup, check, deny } = require('internal/process/policy')
const { setup, check, deny } = require('internal/process/policy');
if (experimentalPolicy) {
process.emitWarning('Policies are experimental.',
'ExperimentalWarning');
Expand Down
8 changes: 4 additions & 4 deletions lib/internal/process/policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,16 @@ module.exports = ObjectFreeze({
this.manifest.assertIntegrity(moduleURL, content);
},

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

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

return policy.check(permission);
return policy.check(permission, params);
}
});
3 changes: 3 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@
'src/string_bytes.cc',
'src/string_decoder.cc',
'src/policy/policy.cc',
'src/policy/policy_deny_fs.cc',
'src/tcp_wrap.cc',
'src/timers.cc',
'src/timer_wrap.cc',
Expand Down Expand Up @@ -637,6 +638,8 @@
'src/node_worker.h',
'src/pipe_wrap.h',
'src/policy/policy.h',
'src/policy/policy_deny.h',
'src/policy/policy_deny_fs.h',
'src/req_wrap.h',
'src/req_wrap-inl.h',
'src/spawn_sync.h',
Expand Down
3 changes: 2 additions & 1 deletion src/fs_event_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ 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 All @@ -146,6 +145,8 @@ void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {

BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, *path);

unsigned int flags = 0;
if (args[2]->IsTrue())
Expand Down
5 changes: 3 additions & 2 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -859,9 +859,10 @@ 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()) {
per_process::cli_options->policy_deny_fs,
policy::Permission::kFileSystem).IsNothing()) {
errors->emplace_back(
"invalid permissions passed to --policy-deny");
"invalid permissions passed to --policy-deny-fs");
return 12;
}

Expand Down
43 changes: 27 additions & 16 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -435,9 +435,6 @@ 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 @@ -862,7 +859,6 @@ 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 All @@ -875,6 +871,8 @@ void Access(const FunctionCallbackInfo<Value>& args) {

BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, *path);

FSReqBase* req_wrap_async = GetReqWrap(args, 2);
if (req_wrap_async != nullptr) { // access(path, mode, req)
Expand Down Expand Up @@ -917,12 +915,13 @@ 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();

CHECK(args[0]->IsString());
node::Utf8Value path(isolate, args[0]);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, path.ToString());

if (strlen(*path) != path.length()) {
args.GetReturnValue().Set(Array::New(isolate));
Expand Down Expand Up @@ -1016,10 +1015,11 @@ 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]);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, path.ToString());

uv_fs_t req;
int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
Expand All @@ -1035,13 +1035,14 @@ 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);

BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, *path);

bool use_bigint = args[1]->IsTrue();
FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
Expand All @@ -1067,13 +1068,14 @@ 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);

BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, *path);

bool use_bigint = args[1]->IsTrue();
FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
Expand All @@ -1100,7 +1102,6 @@ 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 @@ -1187,14 +1188,15 @@ 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();
CHECK_GE(argc, 3);

BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, *path);

const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);

Expand Down Expand Up @@ -1604,14 +1606,15 @@ 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();
CHECK_GE(argc, 3);

BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, *path);

const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);

Expand Down Expand Up @@ -1649,14 +1652,15 @@ 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();
CHECK_GE(argc, 3);

BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, *path);

const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);

Expand Down Expand Up @@ -1737,13 +1741,15 @@ 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);

BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
// Open can be called either in write or read
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystem, *path);

CHECK(args[1]->IsInt32());
const int flags = args[1].As<Int32>()->Value();
Expand Down Expand Up @@ -1771,14 +1777,15 @@ 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();
CHECK_GE(argc, 3);

BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, *path);

CHECK(args[1]->IsInt32());
const int flags = args[1].As<Int32>()->Value();
Expand Down Expand Up @@ -1855,6 +1862,8 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {

CHECK(args[0]->IsInt32());
const int fd = args[0].As<Int32>()->Value();
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemOut, fd);

CHECK(Buffer::HasInstance(args[1]));
Local<Object> buffer_obj = args[1].As<Object>();
Expand Down Expand Up @@ -1953,9 +1962,10 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {

const int argc = args.Length();
CHECK_GE(argc, 4);

CHECK(args[0]->IsInt32());
const int fd = args[0].As<Int32>()->Value();
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemOut, fd);

const int64_t pos = GetOffset(args[2]);

Expand Down Expand Up @@ -2051,13 +2061,14 @@ 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);

CHECK(args[0]->IsInt32());
const int fd = args[0].As<Int32>()->Value();
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, policy::Permission::kFileSystemIn, fd);

CHECK(Buffer::HasInstance(args[1]));
Local<Object> buffer_obj = args[1].As<Object>();
Expand Down
6 changes: 3 additions & 3 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -859,9 +859,9 @@ PerProcessOptionsParser::PerProcessOptionsParser(
"force FIPS crypto (cannot be disabled)",
&PerProcessOptions::force_fips_crypto,
kAllowedInEnvironment);
AddOption("--policy-deny",
"denied permissions",
&PerProcessOptions::policy_deny,
AddOption("--policy-deny-fs",
"denied permissions to the filesystem",
&PerProcessOptions::policy_deny_fs,
kAllowedInEnvironment);
AddOption("--secure-heap",
"total size of the OpenSSL secure heap",
Expand Down
2 changes: 1 addition & 1 deletion src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ class PerProcessOptions : public Options {
bool print_v8_help = false;
bool print_version = false;

std::string policy_deny;
std::string policy_deny_fs;

#ifdef NODE_HAVE_I18N_SUPPORT
std::string icu_data_dir;
Expand Down

0 comments on commit 5e7b005

Please sign in to comment.