summaryrefslogtreecommitdiff
path: root/src/node_file.cc
diff options
context:
space:
mode:
authorRafael Gonzaga <rafael.nunu@hotmail.com>2023-02-23 15:11:51 -0300
committerGitHub <noreply@github.com>2023-02-23 18:11:51 +0000
commit00c222593e49d817281bc88a322f41f8dca95885 (patch)
tree29e6fd71f93dd98d8bb3fcd535d49ed80bdeacd5 /src/node_file.cc
parent42be7f6a0335c396810be91c3f3724007029f83d (diff)
downloadnode-new-00c222593e49d817281bc88a322f41f8dca95885.tar.gz
src,process: add permission model
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com> PR-URL: https://github.com/nodejs/node/pull/44004 Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Michaƫl Zasso <targos@protonmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'src/node_file.cc')
-rw-r--r--src/node_file.cc84
1 files changed, 82 insertions, 2 deletions
diff --git a/src/node_file.cc b/src/node_file.cc
index 388d9bf32c..c6d22b51f2 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -19,13 +19,14 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node_file.h" // NOLINT(build/include_inline)
-#include "node_file-inl.h"
#include "aliased_buffer.h"
#include "memory_tracker-inl.h"
#include "node_buffer.h"
#include "node_external_reference.h"
+#include "node_file-inl.h"
#include "node_process-inl.h"
#include "node_stat_watcher.h"
+#include "permission/permission.h"
#include "util-inl.h"
#include "tracing/trace_event.h"
@@ -961,6 +962,7 @@ void AfterScanDir(uv_fs_t* req) {
void Access(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
+
Isolate* isolate = env->isolate();
HandleScope scope(isolate);
@@ -972,6 +974,8 @@ void Access(const FunctionCallbackInfo<Value>& args) {
BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
if (req_wrap_async != nullptr) { // access(path, mode, req)
@@ -1022,6 +1026,8 @@ static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());
node::Utf8Value path(isolate, args[0]);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
if (strlen(*path) != path.length()) {
args.GetReturnValue().Set(Array::New(isolate));
@@ -1118,6 +1124,8 @@ static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());
node::Utf8Value path(env->isolate(), args[0]);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
uv_fs_t req;
int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
@@ -1139,6 +1147,8 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
bool use_bigint = args[1]->IsTrue();
FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
@@ -1280,8 +1290,17 @@ static void Symlink(const FunctionCallbackInfo<Value>& args) {
BufferValue target(isolate, args[0]);
CHECK_NOT_NULL(*target);
+ auto target_view = target.ToStringView();
+ // To avoid bypass the symlink target should be allowed to read and write
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, target_view);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, target_view);
+
BufferValue path(isolate, args[1]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, path.ToStringView());
CHECK(args[2]->IsInt32());
int flags = args[2].As<Int32>()->Value();
@@ -1348,6 +1367,8 @@ static void ReadLink(const FunctionCallbackInfo<Value>& args) {
BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
@@ -1393,8 +1414,18 @@ static void Rename(const FunctionCallbackInfo<Value>& args) {
BufferValue old_path(isolate, args[0]);
CHECK_NOT_NULL(*old_path);
+ auto view_old_path = old_path.ToStringView();
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, view_old_path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, view_old_path);
+
BufferValue new_path(isolate, args[1]);
CHECK_NOT_NULL(*new_path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env,
+ permission::PermissionScope::kFileSystemWrite,
+ new_path.ToStringView());
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
if (req_wrap_async != nullptr) {
@@ -1498,6 +1529,8 @@ static void Unlink(const FunctionCallbackInfo<Value>& args) {
BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, path.ToStringView());
FSReqBase* req_wrap_async = GetReqWrap(args, 1);
if (req_wrap_async != nullptr) {
@@ -1522,6 +1555,8 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) {
BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, path.ToStringView());
FSReqBase* req_wrap_async = GetReqWrap(args, 1); // rmdir(path, req)
if (req_wrap_async != nullptr) {
@@ -1729,6 +1764,8 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, path.ToStringView());
CHECK(args[1]->IsInt32());
const int mode = args[1].As<Int32>()->Value();
@@ -1827,6 +1864,8 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) {
BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
@@ -1925,6 +1964,23 @@ static void Open(const FunctionCallbackInfo<Value>& args) {
CHECK(args[2]->IsInt32());
const int mode = args[2].As<Int32>()->Value();
+ auto pathView = path.ToStringView();
+ // Open can be called either in write or read
+ if (flags == O_RDWR) {
+ // TODO(rafaelgss): it can be optimized to avoid O(2*n)
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, pathView);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, pathView);
+ } else if ((flags & ~(UV_FS_O_RDONLY | UV_FS_O_SYNC)) == 0) {
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, pathView);
+ } else if ((flags & (UV_FS_O_APPEND | UV_FS_O_TRUNC | UV_FS_O_CREAT |
+ UV_FS_O_WRONLY)) != 0) {
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, pathView);
+ }
+
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
if (req_wrap_async != nullptr) { // open(path, flags, mode, req)
req_wrap_async->set_is_plain_open(true);
@@ -1954,6 +2010,9 @@ static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
+ auto pathView = path.ToStringView();
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, pathView);
CHECK(args[1]->IsInt32());
const int flags = args[1].As<Int32>()->Value();
@@ -1961,6 +2020,22 @@ static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
CHECK(args[2]->IsInt32());
const int mode = args[2].As<Int32>()->Value();
+ // Open can be called either in write or read
+ if (flags == O_RDWR) {
+ // TODO(rafaelgss): it can be optimized to avoid O(2*n)
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, pathView);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, pathView);
+ } else if ((flags & ~(UV_FS_O_RDONLY | UV_FS_O_SYNC)) == 0) {
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, pathView);
+ } else if ((flags & (UV_FS_O_APPEND | UV_FS_O_TRUNC | UV_FS_O_CREAT |
+ UV_FS_O_WRONLY)) != 0) {
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, pathView);
+ }
+
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
if (req_wrap_async != nullptr) { // openFileHandle(path, flags, mode, req)
FS_ASYNC_TRACE_BEGIN1(
@@ -1992,9 +2067,13 @@ static void CopyFile(const FunctionCallbackInfo<Value>& args) {
BufferValue src(isolate, args[0]);
CHECK_NOT_NULL(*src);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemRead, src.ToStringView());
BufferValue dest(isolate, args[1]);
CHECK_NOT_NULL(*dest);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView());
CHECK(args[2]->IsInt32());
const int flags = args[2].As<Int32>()->Value();
@@ -2138,7 +2217,6 @@ 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();
@@ -2503,6 +2581,8 @@ static void UTimes(const FunctionCallbackInfo<Value>& args) {
BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);
+ THROW_IF_INSUFFICIENT_PERMISSIONS(
+ env, permission::PermissionScope::kFileSystemWrite, path.ToStringView());
CHECK(args[1]->IsNumber());
const double atime = args[1].As<Number>()->Value();