Skip to content

Commit b5fec69

Browse files
committed
src: use policy per environment
1 parent ca0ebe3 commit b5fec69

File tree

11 files changed

+83
-72
lines changed

11 files changed

+83
-72
lines changed

src/env-inl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ inline TickInfo* Environment::tick_info() {
335335
return &tick_info_;
336336
}
337337

338+
inline policy::Policy* Environment::policy() {
339+
return &policy_;
340+
}
341+
338342
inline uint64_t Environment::timer_base() const {
339343
return timer_base_;
340344
}

src/env.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,10 @@ Environment::Environment(IsolateData* isolate_data,
884884
"args",
885885
std::move(traced_value));
886886
}
887+
888+
policy()->Apply(
889+
options_->policy_deny_fs,
890+
policy::Permission::kFileSystem);
887891
}
888892

889893
Environment::Environment(IsolateData* isolate_data,

src/env.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "util.h"
4444
#include "uv.h"
4545
#include "v8.h"
46+
#include "policy/policy.h"
4647

4748
#include <array>
4849
#include <atomic>
@@ -1159,6 +1160,7 @@ class Environment : public MemoryRetainer {
11591160
inline ImmediateInfo* immediate_info();
11601161
inline TickInfo* tick_info();
11611162
inline uint64_t timer_base() const;
1163+
inline policy::Policy* policy();
11621164
inline std::shared_ptr<KVStore> env_vars();
11631165
inline void set_env_vars(std::shared_ptr<KVStore> env_vars);
11641166

@@ -1525,6 +1527,7 @@ class Environment : public MemoryRetainer {
15251527
AsyncHooks async_hooks_;
15261528
ImmediateInfo immediate_info_;
15271529
TickInfo tick_info_;
1530+
policy::Policy policy_;
15281531
const uint64_t timer_base_;
15291532
std::shared_ptr<KVStore> env_vars_;
15301533
bool printed_error_ = false;

src/node.cc

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -858,14 +858,6 @@ int ProcessGlobalArgs(std::vector<std::string>* args,
858858

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

861-
if (policy::root_policy.Apply(
862-
per_process::cli_options->policy_deny_fs,
863-
policy::Permission::kFileSystem).IsNothing()) {
864-
errors->emplace_back(
865-
"invalid permissions passed to --policy-deny-fs");
866-
return 12;
867-
}
868-
869861
return 0;
870862
}
871863

src/node_options.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
380380
&EnvironmentOptions::experimental_policy_integrity,
381381
kAllowedInEnvironment);
382382
Implies("--policy-integrity", "[has_policy_integrity_string]");
383+
384+
AddOption("--policy-deny-fs",
385+
"denied permissions to the filesystem",
386+
&EnvironmentOptions::policy_deny_fs,
387+
kAllowedInEnvironment);
383388
AddOption("--experimental-repl-await",
384389
"experimental await keyword support in REPL",
385390
&EnvironmentOptions::experimental_repl_await,
@@ -859,10 +864,6 @@ PerProcessOptionsParser::PerProcessOptionsParser(
859864
"force FIPS crypto (cannot be disabled)",
860865
&PerProcessOptions::force_fips_crypto,
861866
kAllowedInEnvironment);
862-
AddOption("--policy-deny-fs",
863-
"denied permissions to the filesystem",
864-
&PerProcessOptions::policy_deny_fs,
865-
kAllowedInEnvironment);
866867
AddOption("--secure-heap",
867868
"total size of the OpenSSL secure heap",
868869
&PerProcessOptions::secure_heap,

src/node_options.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class EnvironmentOptions : public Options {
118118
std::string experimental_policy;
119119
std::string experimental_policy_integrity;
120120
bool has_policy_integrity_string = false;
121+
std::string policy_deny_fs;
121122
bool experimental_repl_await = true;
122123
bool experimental_vm_modules = false;
123124
bool expose_internals = false;
@@ -244,8 +245,6 @@ class PerProcessOptions : public Options {
244245
bool print_v8_help = false;
245246
bool print_version = false;
246247

247-
std::string policy_deny_fs;
248-
249248
#ifdef NODE_HAVE_I18N_SUPPORT
250249
std::string icu_data_dir;
251250
#endif

src/policy/policy.cc

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88

99
#include "v8.h"
1010

11+
#include <iostream>
12+
#include <memory>
1113
#include <string>
1214
#include <vector>
13-
#include <iostream>
1415

1516
namespace node {
1617

@@ -28,10 +29,6 @@ using v8::Value;
2829

2930
namespace policy {
3031

31-
// The root policy is establish at process start using
32-
// the --policy-deny-* command line arguments.
33-
Policy root_policy;
34-
3532
namespace {
3633

3734
// policy.deny('fs.in', ['/tmp/'])
@@ -43,26 +40,30 @@ static void Deny(const FunctionCallbackInfo<Value>& args) {
4340
CHECK(args[0]->IsString());
4441
CHECK(args.Length() >= 2 || args[1]->IsArray());
4542

46-
std::string denyScope = *String::Utf8Value(isolate, args[0]);
47-
Permission scope = Policy::StringToPermission(denyScope);
43+
std::string deny_scope = *String::Utf8Value(isolate, args[0]);
44+
Permission scope = Policy::StringToPermission(deny_scope);
4845
if (scope == Permission::kPermissionsRoot) {
4946
return args.GetReturnValue().Set(false);
5047
}
5148

52-
Local<Array> jsParams = Local<Array>::Cast(args[1]);
53-
std::vector<std::string> params;
54-
for (uint32_t i = 0; i < jsParams->Length(); ++i) {
55-
Local<Value> arg(
56-
jsParams
57-
->Get(isolate->GetCurrentContext(), Integer::New(isolate, i))
58-
.ToLocalChecked());
49+
Local<Array> js_params = Local<Array>::Cast(args[1]);
50+
Local<Context> context = isolate->GetCurrentContext();
5951

52+
std::vector<std::string> params;
53+
for (uint32_t i = 0; i < js_params->Length(); ++i) {
54+
Local<Value> arg;
55+
if (!js_params->Get(context, Integer::New(isolate, i)).ToLocal(&arg)) {
56+
return;
57+
}
6058
String::Utf8Value utf8_arg(isolate, arg);
59+
if (*utf8_arg == nullptr) {
60+
return;
61+
}
6162
params.push_back(*utf8_arg);
6263
}
6364

6465
return args.GetReturnValue()
65-
.Set(root_policy.Deny(scope, params));
66+
.Set(env->policy()->Deny(scope, params));
6667
}
6768

6869
// policy.check('fs.in', '/tmp/')
@@ -73,15 +74,23 @@ static void Check(const FunctionCallbackInfo<Value>& args) {
7374
CHECK(args[0]->IsString());
7475
CHECK(args.Length() >= 2 || args[1]->IsString());
7576

76-
std::string denyScope = *String::Utf8Value(isolate, args[0]);
77-
Permission scope = Policy::StringToPermission(denyScope);
77+
String::Utf8Value utf8_deny_scope(isolate, args[0]);
78+
if (*utf8_deny_scope == nullptr) {
79+
return;
80+
}
81+
82+
const std::string deny_scope = *utf8_deny_scope;
83+
Permission scope = Policy::StringToPermission(deny_scope);
7884
if (scope == Permission::kPermissionsRoot) {
79-
// TODO(rafaelgss): throw?
8085
return args.GetReturnValue().Set(false);
8186
}
8287

83-
return args.GetReturnValue()
84-
.Set(root_policy.is_granted(scope, *String::Utf8Value(isolate, args[1])));
88+
String::Utf8Value utf8_arg(isolate, args[1]);
89+
if (*utf8_arg == nullptr) {
90+
return;
91+
}
92+
93+
return args.GetReturnValue().Set(env->policy()->is_granted(scope, *utf8_arg));
8594
}
8695

8796
} // namespace
@@ -96,7 +105,7 @@ const char* Policy::PermissionToString(const Permission perm) {
96105

97106
#define V(Name, label, _) \
98107
if (perm == label) return Permission::k##Name;
99-
Permission Policy::StringToPermission(std::string perm) {
108+
Permission Policy::StringToPermission(const std::string& perm) {
100109
PERMISSIONS(V)
101110
return Permission::kPermissionsRoot;
102111
}
@@ -123,7 +132,7 @@ Maybe<bool> Policy::Apply(const std::string& deny, Permission scope) {
123132
return Just(false);
124133
}
125134

126-
bool Policy::Deny(Permission scope, std::vector<std::string> params) {
135+
bool Policy::Deny(Permission scope, const std::vector<std::string>& params) {
127136
auto policy = deny_policies.find(scope);
128137
if (policy != deny_policies.end()) {
129138
return policy->second->Deny(scope, params);

src/policy/policy.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,17 @@ class Environment;
1818
namespace policy {
1919

2020
#define THROW_IF_INSUFFICIENT_PERMISSIONS(env, perm_, resource_, ...) \
21-
if (!node::policy::root_policy.is_granted(perm_, resource_)) { \
21+
if (!env->policy()->is_granted(perm_, resource_)) { \
2222
return node::policy::Policy::ThrowAccessDenied((env), perm_); \
2323
}
2424

2525
class Policy {
2626
public:
27-
// TODO(rafaelgss): release pointers
2827
Policy() {
29-
auto denyFs = new PolicyDenyFs();
30-
#define V(Name, _, __) \
31-
deny_policies.insert(std::make_pair(Permission::k##Name, denyFs));
32-
FILESYSTEM_PERMISSIONS(V)
28+
std::shared_ptr<PolicyDeny> deny_fs = std::make_shared<PolicyDenyFs>();
29+
#define V(Name, _, __) \
30+
deny_policies.insert(std::make_pair(Permission::k##Name, deny_fs));
31+
FILESYSTEM_PERMISSIONS(V)
3332
#undef V
3433
}
3534

@@ -45,20 +44,19 @@ class Policy {
4544
return is_granted(permission, res.c_str());
4645
}
4746

48-
static Permission StringToPermission(std::string perm);
47+
static Permission StringToPermission(const std::string& perm);
4948
static const char* PermissionToString(Permission perm);
5049
static void ThrowAccessDenied(Environment* env, Permission perm);
5150

5251
// CLI Call
5352
v8::Maybe<bool> Apply(const std::string& deny, Permission scope);
5453
// Policy.Deny API
55-
bool Deny(Permission scope, std::vector<std::string> params);
54+
bool Deny(Permission scope, const std::vector<std::string>& params);
5655

5756
private:
58-
std::map<Permission, PolicyDeny*> deny_policies;
57+
std::map<Permission, std::shared_ptr<PolicyDeny>> deny_policies;
5958
};
6059

61-
extern policy::Policy root_policy;
6260
} // namespace policy
6361

6462
} // namespace node

src/policy/policy_deny.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ enum class Permission {
3030
class PolicyDeny {
3131
public:
3232
virtual v8::Maybe<bool> Apply(const std::string& deny) = 0;
33-
virtual bool Deny(Permission scope, std::vector<std::string> params) = 0;
33+
virtual bool Deny(Permission scope,
34+
const std::vector<std::string>& params) = 0;
3435
virtual bool is_granted(Permission perm, const std::string& param = "") = 0;
3536
};
3637

src/policy/policy_deny_fs.cc

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ Maybe<bool> PolicyDenyFs::Apply(const std::string& deny) {
4848
return Just(true);
4949
}
5050

51-
bool PolicyDenyFs::Deny(Permission perm, std::vector<std::string> params) {
51+
bool PolicyDenyFs::Deny(Permission perm,
52+
const std::vector<std::string>& params) {
5253
if (perm == Permission::kFileSystem) {
5354
deny_all_in_ = true;
5455
deny_all_out_ = true;
@@ -78,25 +79,25 @@ bool PolicyDenyFs::Deny(Permission perm, std::vector<std::string> params) {
7879
}
7980

8081
void PolicyDenyFs::RestrictAccess(Permission perm, const std::string& res) {
81-
char resolvedPath[PATH_MAX];
82+
char resolved_path[PATH_MAX];
8283
// check the result
83-
realpath(res.c_str(), resolvedPath);
84+
realpath(res.c_str(), resolved_path);
8485

85-
std::filesystem::path path(resolvedPath);
86+
std::filesystem::path path(resolved_path);
8687
bool isDir = std::filesystem::is_directory(path);
8788
// when there are parameters deny_params_ is automatically
8889
// set to false
8990
if (perm == Permission::kFileSystemIn) {
9091
deny_all_in_ = false;
91-
deny_in_params_.push_back(std::make_pair(resolvedPath, isDir));
92+
deny_in_params_.push_back(std::make_pair(resolved_path, isDir));
9293
} else if (perm == Permission::kFileSystemOut) {
9394
deny_all_out_ = false;
94-
deny_out_params_.push_back(std::make_pair(resolvedPath, isDir));
95+
deny_out_params_.push_back(std::make_pair(resolved_path, isDir));
9596
}
9697
}
9798

9899
void PolicyDenyFs::RestrictAccess(Permission perm,
99-
std::vector<std::string> params) {
100+
const std::vector<std::string>& params) {
100101
for (auto& param : params) {
101102
RestrictAccess(perm, param);
102103
}
@@ -118,15 +119,15 @@ bool PolicyDenyFs::is_granted(Permission perm, const std::string& param = "") {
118119
}
119120

120121
bool PolicyDenyFs::is_granted(DenyFsParams params, const std::string& opt) {
121-
char resolvedPath[PATH_MAX];
122-
realpath(opt.c_str(), resolvedPath);
122+
char resolved_path[PATH_MAX];
123+
realpath(opt.c_str(), resolved_path);
123124
for (auto& param : params) {
124125
// is folder
125126
if (param.second) {
126-
if (strstr(resolvedPath, param.first.c_str()) == resolvedPath) {
127+
if (strstr(resolved_path, param.first.c_str()) == resolved_path) {
127128
return false;
128129
}
129-
} else if (param.first == resolvedPath) {
130+
} else if (param.first == resolved_path) {
130131
return false;
131132
}
132133
}

src/policy/policy_deny_fs.h

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,28 @@
88
#include "policy/policy_deny.h"
99
#include <vector>
1010

11-
using v8::Maybe;
12-
1311
namespace node {
1412

1513
namespace policy {
1614

1715
using DenyFsParams = std::vector<std::pair<std::string, bool /* is_folder */>>;
1816

1917
// TODO(rafaelgss): implement radix-tree algorithm
20-
class PolicyDenyFs : public PolicyDeny {
18+
class PolicyDenyFs final : public PolicyDeny {
2119
public:
22-
Maybe<bool> Apply(const std::string& deny);
23-
bool Deny(Permission scope, std::vector<std::string> params);
24-
bool is_granted(Permission perm, const std::string& param);
20+
v8::Maybe<bool> Apply(const std::string& deny) override;
21+
bool Deny(Permission scope, const std::vector<std::string>& params) override;
22+
bool is_granted(Permission perm, const std::string& param) override;
23+
2524
private:
26-
static bool is_granted(DenyFsParams params, const std::string& opt);
27-
void RestrictAccess(Permission scope, const std::string& param);
28-
void RestrictAccess(Permission scope, std::vector<std::string> params);
29-
30-
DenyFsParams deny_in_params_;
31-
DenyFsParams deny_out_params_;
32-
bool deny_all_in_;
33-
bool deny_all_out_;
25+
static bool is_granted(DenyFsParams params, const std::string& opt);
26+
void RestrictAccess(Permission scope, const std::string& param);
27+
void RestrictAccess(Permission scope, const std::vector<std::string>& params);
28+
29+
DenyFsParams deny_in_params_;
30+
DenyFsParams deny_out_params_;
31+
bool deny_all_in_;
32+
bool deny_all_out_;
3433
};
3534

3635
} // namespace policy

0 commit comments

Comments
 (0)