Skip to content
Draft
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
3 changes: 3 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ to use as a custom module loader.
.It Fl -permission
Enable the permission model.
.
.It Fl -permission-audit
Enable warning only with the permission model.
.
.It Fl -experimental-shadow-realm
Use this flag to enable ShadowRealm support.
.
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ function initializeClusterIPC() {
}

function initializePermission() {
const permission = getOptionValue('--permission');
const permission = getOptionValue('--permission') || getOptionValue('--permission-audit');
if (permission) {
process.binding = function binding(_module) {
throw new ERR_ACCESS_DENIED('process.binding');
Expand Down
5 changes: 4 additions & 1 deletion src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -909,8 +909,11 @@ Environment::Environment(IsolateData* isolate_data,
tracing::CastTracedValue(traced_value));
}

if (options_->permission) {
if (options_->permission || options_->permission_audit) {
permission()->EnablePermissions();
if (options_->permission_audit) {
permission()->EnableWarningOnly();
}
// The process shouldn't be able to neither
// spawn/worker nor use addons or enable inspector
// unless explicitly allowed by the user
Expand Down
5 changes: 5 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
&EnvironmentOptions::permission,
kAllowedInEnvvar,
false);
AddOption("--permission-audit",
"enable audit only for the permission system",
&EnvironmentOptions::permission_audit,
kAllowedInEnvvar,
false);
AddOption("--allow-fs-read",
"allow permissions to read the filesystem",
&EnvironmentOptions::allow_fs_read,
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ class EnvironmentOptions : public Options {
std::string input_type; // Value of --input-type
bool entry_is_url = false;
bool permission = false;
bool permission_audit = false;
std::vector<std::string> allow_fs_read;
std::vector<std::string> allow_fs_write;
bool allow_addons = false;
Expand Down
8 changes: 8 additions & 0 deletions src/node_process-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ inline v8::Maybe<bool> ProcessEmitWarning(Environment* env,
return ProcessEmitWarningGeneric(env, warning.c_str());
}

template <typename... Args>
inline v8::Maybe<void> ProcessEmitWarningSync(Environment* env,
const char* fmt,
Args&&... args) {
std::string warning = SPrintF(fmt, std::forward<Args>(args)...);
return ProcessEmitWarningSync(env, warning);
}

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Expand Down
4 changes: 4 additions & 0 deletions src/node_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ template <typename... Args>
inline v8::Maybe<bool> ProcessEmitWarning(Environment* env,
const char* fmt,
Args&&... args);
template <typename... Args>
inline v8::Maybe<void> ProcessEmitWarningSync(Environment* env,
const char* fmt,
Args&&... args);

v8::Maybe<void> ProcessEmitWarningSync(Environment* env,
std::string_view message);
Expand Down
50 changes: 39 additions & 11 deletions src/permission/permission.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_file.h"
#include "node_process-inl.h"

#include "v8.h"

Expand Down Expand Up @@ -70,7 +71,7 @@ PermissionScope Permission::StringToPermission(const std::string& perm) {
}
#undef V

Permission::Permission() : enabled_(false) {
Permission::Permission() : enabled_(false), warning_only_(false) {
std::shared_ptr<PermissionBase> fs = std::make_shared<FSPermission>();
std::shared_ptr<PermissionBase> child_p =
std::make_shared<ChildProcessPermission>();
Expand Down Expand Up @@ -149,24 +150,45 @@ MaybeLocal<Value> CreateAccessDeniedError(Environment* env,
void Permission::ThrowAccessDenied(Environment* env,
PermissionScope perm,
const std::string_view& res) {
Local<Value> err;
if (CreateAccessDeniedError(env, perm, res).ToLocal(&err)) {
env->isolate()->ThrowException(err);
// If permission is set to "audit" only. We should not throw, but
// emit warning whenever a permission is "bypassed"
if (!env->permission()->warning_only()) {
Local<Value> err;
if (CreateAccessDeniedError(env, perm, res).ToLocal(&err)) {
env->isolate()->ThrowException(err);
}
// If ToLocal returned false, then v8 will have scheduled a
// superseding error to be thrown.
return;
}
// If ToLocal returned false, then v8 will have scheduled a
// superseding error to be thrown.
std::string_view perm_str = Permission::PermissionToString(perm);
ProcessEmitWarningSync(
env,
"ERR_ACCESS_DENIED suppressed. Permission: %s, Resource: %s",
perm_str,
res);
}

void Permission::AsyncThrowAccessDenied(Environment* env,
fs::FSReqBase* req_wrap,
PermissionScope perm,
const std::string_view& res) {
Local<Value> err;
if (CreateAccessDeniedError(env, perm, res).ToLocal(&err)) {
return req_wrap->Reject(err);
if (env->permission()->warning_only()) {
Local<Value> err;
if (CreateAccessDeniedError(env, perm, res).ToLocal(&err)) {
return req_wrap->Reject(err);
}
// If ToLocal returned false, then v8 will have scheduled a
// superseding error to be thrown.
return;
}
// If ToLocal returned false, then v8 will have scheduled a
// superseding error to be thrown.
std::string_view perm_str = Permission::PermissionToString(perm);
// TODO: handle warning error
ProcessEmitWarning(
env,
"ERR_ACCESS_DENIED suppressed. Permission: %s, Resource: %s",
perm_str,
res);
}

void Permission::EnablePermissions() {
Expand All @@ -175,6 +197,12 @@ void Permission::EnablePermissions() {
}
}

void Permission::EnableWarningOnly() {
if (!warning_only_) {
warning_only_ = true;
}
}

void Permission::Apply(Environment* env,
const std::vector<std::string>& allow,
PermissionScope scope) {
Expand Down
10 changes: 7 additions & 3 deletions src/permission/permission.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace permission {
[[unlikely]] { \
node::permission::Permission::ThrowAccessDenied( \
env__, perm__, resource__); \
return __VA_ARGS__; \
if (!env__->permission()->warning_only()) return __VA_ARGS__; \
} \
} while (0)

Expand All @@ -51,7 +51,7 @@ namespace permission {
[[unlikely]] { \
node::permission::Permission::AsyncThrowAccessDenied( \
env__, (wrap), perm__, resource__); \
return __VA_ARGS__; \
if (!env__->permission()->warning_only()) return __VA_ARGS__; \
} \
} while (0)

Expand All @@ -66,7 +66,7 @@ namespace permission {
Local<Value> err_access; \
if (node::permission::CreateAccessDeniedError(env__, perm__, resource__) \
.ToLocal(&err_access)) { \
args.GetReturnValue().Set(err_access); \
\ args.GetReturnValue().Set(err_access); \
} else { \
args.GetReturnValue().Set(UV_EACCES); \
} \
Expand Down Expand Up @@ -100,6 +100,8 @@ class Permission {

FORCE_INLINE bool enabled() const { return enabled_; }

FORCE_INLINE bool warning_only() const { return warning_only_; }

static PermissionScope StringToPermission(const std::string& perm);
static const char* PermissionToString(PermissionScope perm);
static void ThrowAccessDenied(Environment* env,
Expand All @@ -115,6 +117,7 @@ class Permission {
const std::vector<std::string>& allow,
PermissionScope scope);
void EnablePermissions();
void EnableWarningOnly();

private:
COLD_NOINLINE bool is_scope_granted(Environment* env,
Expand All @@ -129,6 +132,7 @@ class Permission {

std::unordered_map<PermissionScope, std::shared_ptr<PermissionBase>> nodes_;
bool enabled_;
bool warning_only_;
};

v8::MaybeLocal<v8::Value> CreateAccessDeniedError(Environment* env,
Expand Down