| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b616f6f commit 3badc11
18 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -142,6 +142,7 @@ | |||
| 142 | 142 | 'src/node_watchdog.cc', | |
| 143 | 143 | 'src/node_worker.cc', | |
| 144 | 144 | 'src/node_zlib.cc', | |
| 145 | + 'src/path.cc', | ||
| 145 | 146 | 'src/permission/child_process_permission.cc', | |
| 146 | 147 | 'src/permission/fs_permission.cc', | |
| 147 | 148 | 'src/permission/inspector_permission.cc', | |
@@ -262,6 +263,7 @@ | |||
| 262 | 263 | 'src/node_wasi.h', | |
| 263 | 264 | 'src/node_watchdog.h', | |
| 264 | 265 | 'src/node_worker.h', | |
| 266 | + 'src/path.h', | ||
| 265 | 267 | 'src/permission/child_process_permission.h', | |
| 266 | 268 | 'src/permission/fs_permission.h', | |
| 267 | 269 | 'src/permission/inspector_permission.h', | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -898,21 +898,25 @@ Environment::Environment(IsolateData* isolate_data, | |||
| 898 | 898 | options_->allow_native_addons = false; | |
| 899 | 899 | } | |
| 900 | 900 | flags_ = flags_ | EnvironmentFlags::kNoCreateInspector; | |
| 901 | - permission()->Apply({"*"}, permission::PermissionScope::kInspector); | ||
| 901 | + permission()->Apply(this, {"*"}, permission::PermissionScope::kInspector); | ||
| 902 | 902 | if (!options_->allow_child_process) { | |
| 903 | - permission()->Apply({"*"}, permission::PermissionScope::kChildProcess); | ||
| 903 | + permission()->Apply( | ||
| 904 | + this, {"*"}, permission::PermissionScope::kChildProcess); | ||
| 904 | 905 | } | |
| 905 | 906 | if (!options_->allow_worker_threads) { | |
| 906 | - permission()->Apply({"*"}, permission::PermissionScope::kWorkerThreads); | ||
| 907 | + permission()->Apply( | ||
| 908 | + this, {"*"}, permission::PermissionScope::kWorkerThreads); | ||
| 907 | 909 | } | |
| 908 | 910 | ||
| 909 | 911 | if (!options_->allow_fs_read.empty()) { | |
| 910 | - permission()->Apply(options_->allow_fs_read, | ||
| 912 | + permission()->Apply(this, | ||
| 913 | + options_->allow_fs_read, | ||
| 911 | 914 | permission::PermissionScope::kFileSystemRead); | |
| 912 | 915 | } | |
| 913 | 916 | ||
| 914 | 917 | if (!options_->allow_fs_write.empty()) { | |
| 915 | - permission()->Apply(options_->allow_fs_write, | ||
| 918 | + permission()->Apply(this, | ||
| 919 | + options_->allow_fs_write, | ||
| 916 | 920 | permission::PermissionScope::kFileSystemWrite); | |
| 917 | 921 | } | |
| 918 | 922 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,272 @@ | |||
| 1 | + #include "path.h" | ||
| 2 | + #include <string> | ||
| 3 | + #include <vector> | ||
| 4 | + #include "env-inl.h" | ||
| 5 | + #include "node_internals.h" | ||
| 6 | + #include "util.h" | ||
| 7 | + | ||
| 8 | + namespace node { | ||
| 9 | + | ||
| 10 | + #ifdef _WIN32 | ||
| 11 | + bool IsPathSeparator(const char c) noexcept { | ||
| 12 | + return c == kPathSeparator || c == '/'; | ||
| 13 | + } | ||
| 14 | + #else // POSIX | ||
| 15 | + bool IsPathSeparator(const char c) noexcept { | ||
| 16 | + return c == kPathSeparator; | ||
| 17 | + } | ||
| 18 | + #endif // _WIN32 | ||
| 19 | + | ||
| 20 | + std::string NormalizeString(const std::string_view path, | ||
| 21 | + bool allowAboveRoot, | ||
| 22 | + const std::string_view separator) { | ||
| 23 | + std::string res; | ||
| 24 | + int lastSegmentLength = 0; | ||
| 25 | + int lastSlash = -1; | ||
| 26 | + int dots = 0; | ||
| 27 | + char code; | ||
| 28 | + const auto pathLen = path.size(); | ||
| 29 | + for (uint8_t i = 0; i <= pathLen; ++i) { | ||
| 30 | + if (i < pathLen) { | ||
| 31 | + code = path[i]; | ||
| 32 | + } else if (IsPathSeparator(path[i])) { | ||
| 33 | + break; | ||
| 34 | + } else { | ||
| 35 | + code = node::kPathSeparator; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + if (IsPathSeparator(code)) { | ||
| 39 | + if (lastSlash == static_cast<int>(i - 1) || dots == 1) { | ||
| 40 | + // NOOP | ||
| 41 | + } else if (dots == 2) { | ||
| 42 | + int len = res.length(); | ||
| 43 | + if (len < 2 || lastSegmentLength != 2 || res[len - 1] != '.' || | ||
| 44 | + res[len - 2] != '.') { | ||
| 45 | + if (len > 2) { | ||
| 46 | + auto lastSlashIndex = res.find_last_of(separator); | ||
| 47 | + if (lastSlashIndex == std::string::npos) { | ||
| 48 | + res = ""; | ||
| 49 | + lastSegmentLength = 0; | ||
| 50 | + } else { | ||
| 51 | + res = res.substr(0, lastSlashIndex); | ||
| 52 | + len = res.length(); | ||
| 53 | + lastSegmentLength = len - 1 - res.find_last_of(separator); | ||
| 54 | + } | ||
| 55 | + lastSlash = i; | ||
| 56 | + dots = 0; | ||
| 57 | + continue; | ||
| 58 | + } else if (len != 0) { | ||
| 59 | + res = ""; | ||
| 60 | + lastSegmentLength = 0; | ||
| 61 | + lastSlash = i; | ||
| 62 | + dots = 0; | ||
| 63 | + continue; | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + if (allowAboveRoot) { | ||
| 68 | + res += res.length() > 0 ? std::string(separator) + ".." : ".."; | ||
| 69 | + lastSegmentLength = 2; | ||
| 70 | + } | ||
| 71 | + } else { | ||
| 72 | + if (!res.empty()) { | ||
| 73 | + res += std::string(separator) + | ||
| 74 | + std::string(path.substr(lastSlash + 1, i - (lastSlash + 1))); | ||
| 75 | + } else { | ||
| 76 | + res = path.substr(lastSlash + 1, i - (lastSlash + 1)); | ||
| 77 | + } | ||
| 78 | + lastSegmentLength = i - lastSlash - 1; | ||
| 79 | + } | ||
| 80 | + lastSlash = i; | ||
| 81 | + dots = 0; | ||
| 82 | + } else if (code == '.' && dots != -1) { | ||
| 83 | + ++dots; | ||
| 84 | + } else { | ||
| 85 | + dots = -1; | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + return res; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + #ifdef _WIN32 | ||
| 93 | + bool IsWindowsDeviceRoot(const char c) noexcept { | ||
| 94 | + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + std::string PathResolve(Environment* env, | ||
| 98 | + const std::vector<std::string_view>& paths) { | ||
| 99 | + std::string resolvedDevice = ""; | ||
| 100 | + std::string resolvedTail = ""; | ||
| 101 | + bool resolvedAbsolute = false; | ||
| 102 | + const size_t numArgs = paths.size(); | ||
| 103 | + auto cwd = env->GetCwd(env->exec_path()); | ||
| 104 | + | ||
| 105 | + for (int i = numArgs - 1; i >= -1 && !resolvedAbsolute; i--) { | ||
| 106 | + std::string path; | ||
| 107 | + if (i >= 0) { | ||
| 108 | + path = std::string(paths[i]); | ||
| 109 | + } else if (resolvedDevice.empty()) { | ||
| 110 | + path = cwd; | ||
| 111 | + } else { | ||
| 112 | + // Windows has the concept of drive-specific current working | ||
| 113 | + // directories. If we've resolved a drive letter but not yet an | ||
| 114 | + // absolute path, get cwd for that drive, or the process cwd if | ||
| 115 | + // the drive cwd is not available. We're sure the device is not | ||
| 116 | + // a UNC path at this points, because UNC paths are always absolute. | ||
| 117 | + std::string resolvedDevicePath; | ||
| 118 | + const std::string envvar = "=" + resolvedDevice; | ||
| 119 | + credentials::SafeGetenv(envvar.c_str(), &resolvedDevicePath); | ||
| 120 | + path = resolvedDevicePath.empty() ? cwd : resolvedDevicePath; | ||
| 121 | + | ||
| 122 | + // Verify that a cwd was found and that it actually points | ||
| 123 | + // to our drive. If not, default to the drive's root. | ||
| 124 | + if (path.empty() || | ||
| 125 | + (ToLower(path.substr(0, 2)) != ToLower(resolvedDevice) && | ||
| 126 | + path[2] == '/')) { | ||
| 127 | + path = resolvedDevice + "\\"; | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + const size_t len = path.length(); | ||
| 132 | + int rootEnd = 0; | ||
| 133 | + std::string device = ""; | ||
| 134 | + bool isAbsolute = false; | ||
| 135 | + const char code = path[0]; | ||
| 136 | + | ||
| 137 | + // Try to match a root | ||
| 138 | + if (len == 1) { | ||
| 139 | + if (IsPathSeparator(code)) { | ||
| 140 | + // `path` contains just a path separator | ||
| 141 | + rootEnd = 1; | ||
| 142 | + isAbsolute = true; | ||
| 143 | + } | ||
| 144 | + } else if (IsPathSeparator(code)) { | ||
| 145 | + // Possible UNC root | ||
| 146 | + | ||
| 147 | + // If we started with a separator, we know we at least have an | ||
| 148 | + // absolute path of some kind (UNC or otherwise) | ||
| 149 | + isAbsolute = true; | ||
| 150 | + | ||
| 151 | + if (IsPathSeparator(path[1])) { | ||
| 152 | + // Matched double path separator at beginning | ||
| 153 | + size_t j = 2; | ||
| 154 | + size_t last = j; | ||
| 155 | + // Match 1 or more non-path separators | ||
| 156 | + while (j < len && !IsPathSeparator(path[j])) { | ||
| 157 | + j++; | ||
| 158 | + } | ||
| 159 | + if (j < len && j != last) { | ||
| 160 | + const std::string firstPart = path.substr(last, j - last); | ||
| 161 | + // Matched! | ||
| 162 | + last = j; | ||
| 163 | + // Match 1 or more path separators | ||
| 164 | + while (j < len && IsPathSeparator(path[j])) { | ||
| 165 | + j++; | ||
| 166 | + } | ||
| 167 | + if (j < len && j != last) { | ||
| 168 | + // Matched! | ||
| 169 | + last = j; | ||
| 170 | + // Match 1 or more non-path separators | ||
| 171 | + while (j < len && !IsPathSeparator(path[j])) { | ||
| 172 | + j++; | ||
| 173 | + } | ||
| 174 | + if (j == len || j != last) { | ||
| 175 | + // We matched a UNC root | ||
| 176 | + device = "\\\\" + firstPart + "\\" + path.substr(last, j - last); | ||
| 177 | + rootEnd = j; | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + } | ||
| 181 | + } | ||
| 182 | + } else if (IsWindowsDeviceRoot(code) && path[1] == ':') { | ||
| 183 | + // Possible device root | ||
| 184 | + device = path.substr(0, 2); | ||
| 185 | + rootEnd = 2; | ||
| 186 | + if (len > 2 && IsPathSeparator(path[2])) { | ||
| 187 | + // Treat separator following drive name as an absolute path | ||
| 188 | + // indicator | ||
| 189 | + isAbsolute = true; | ||
| 190 | + rootEnd = 3; | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + if (!device.empty()) { | ||
| 195 | + if (!resolvedDevice.empty()) { | ||
| 196 | + if (ToLower(device) != ToLower(resolvedDevice)) { | ||
| 197 | + // This path points to another device so it is not applicable | ||
| 198 | + continue; | ||
| 199 | + } | ||
| 200 | + } else { | ||
| 201 | + resolvedDevice = device; | ||
| 202 | + } | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + if (resolvedAbsolute) { | ||
| 206 | + if (!resolvedDevice.empty()) { | ||
| 207 | + break; | ||
| 208 | + } | ||
| 209 | + } else { | ||
| 210 | + resolvedTail = path.substr(rootEnd) + "\\" + resolvedTail; | ||
| 211 | + resolvedAbsolute = isAbsolute; | ||
| 212 | + if (isAbsolute && !resolvedDevice.empty()) { | ||
| 213 | + break; | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + // At this point the path should be resolved to a full absolute path, | ||
| 219 | + // but handle relative paths to be safe (might happen when process.cwd() | ||
| 220 | + // fails) | ||
| 221 | + | ||
| 222 | + // Normalize the tail path | ||
| 223 | + resolvedTail = NormalizeString(resolvedTail, !resolvedAbsolute, "\\"); | ||
| 224 | + | ||
| 225 | + if (resolvedAbsolute) { | ||
| 226 | + return resolvedDevice + "\\" + resolvedTail; | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + if (!resolvedDevice.empty() || !resolvedTail.empty()) { | ||
| 230 | + return resolvedDevice + resolvedTail; | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | + return "."; | ||
| 234 | + } | ||
| 235 | + #else // _WIN32 | ||
| 236 | + std::string PathResolve(Environment* env, | ||
| 237 | + const std::vector<std::string_view>& paths) { | ||
| 238 | + std::string resolvedPath; | ||
| 239 | + bool resolvedAbsolute = false; | ||
| 240 | + auto cwd = env->GetCwd(env->exec_path()); | ||
| 241 | + const size_t numArgs = paths.size(); | ||
| 242 | + | ||
| 243 | + for (int i = numArgs - 1; i >= -1 && !resolvedAbsolute; i--) { | ||
| 244 | + const std::string& path = | ||
| 245 | + (i >= 0) ? std::string(paths[i]) : env->GetCwd(env->exec_path()); | ||
| 246 | + | ||
| 247 | + if (!path.empty()) { | ||
| 248 | + resolvedPath = std::string(path) + "/" + resolvedPath; | ||
| 249 | + | ||
| 250 | + if (path.front() == '/') { | ||
| 251 | + resolvedAbsolute = true; | ||
| 252 | + break; | ||
| 253 | + } | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + // Normalize the path | ||
| 258 | + auto normalizedPath = NormalizeString(resolvedPath, !resolvedAbsolute, "/"); | ||
| 259 | + | ||
| 260 | + if (resolvedAbsolute) { | ||
| 261 | + return "/" + normalizedPath; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + if (normalizedPath.empty()) { | ||
| 265 | + return "."; | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + return normalizedPath; | ||
| 269 | + } | ||
| 270 | + #endif // _WIN32 | ||
| 271 | + | ||
| 272 | + } // namespace node | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,25 @@ | |||
| 1 | + #ifndef SRC_PATH_H_ | ||
| 2 | + #define SRC_PATH_H_ | ||
| 3 | + | ||
| 4 | + #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | ||
| 5 | + | ||
| 6 | + #include <string> | ||
| 7 | + #include <vector> | ||
| 8 | + | ||
| 9 | + namespace node { | ||
| 10 | + | ||
| 11 | + class Environment; | ||
| 12 | + | ||
| 13 | + bool IsPathSeparator(const char c) noexcept; | ||
| 14 | + | ||
| 15 | + std::string NormalizeString(const std::string_view path, | ||
| 16 | + bool allowAboveRoot, | ||
| 17 | + const std::string_view separator); | ||
| 18 | + | ||
| 19 | + std::string PathResolve(Environment* env, | ||
| 20 | + const std::vector<std::string_view>& args); | ||
| 21 | + } // namespace node | ||
| 22 | + | ||
| 23 | + #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | ||
| 24 | + | ||
| 25 | + #endif // SRC_PATH_H_ | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,7 +9,8 @@ namespace permission { | |||
| 9 | 9 | ||
| 10 | 10 | // Currently, ChildProcess manage a single state | |
| 11 | 11 | // Once denied, it's always denied | |
| 12 | - void ChildProcessPermission::Apply(const std::vector<std::string>& allow, | ||
| 12 | + void ChildProcessPermission::Apply(Environment* env, | ||
| 13 | + const std::vector<std::string>& allow, | ||
| 13 | 14 | PermissionScope scope) { | |
| 14 | 15 | deny_all_ = true; | |
| 15 | 16 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -12,7 +12,8 @@ namespace permission { | |||
| 12 | 12 | ||
| 13 | 13 | class ChildProcessPermission final : public PermissionBase { | |
| 14 | 14 | public: | |
| 15 | - void Apply(const std::vector<std::string>& allow, | ||
| 15 | + void Apply(Environment* env, | ||
| 16 | + const std::vector<std::string>& allow, | ||
| 16 | 17 | PermissionScope scope) override; | |
| 17 | 18 | bool is_granted(PermissionScope perm, | |
| 18 | 19 | const std::string_view& param = "") const override; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,7 @@ | |||
| 1 | 1 | #include "fs_permission.h" | |
| 2 | 2 | #include "base_object-inl.h" | |
| 3 | 3 | #include "debug_utils-inl.h" | |
| 4 | - #include "util.h" | ||
| 4 | + #include "path.h" | ||
| 5 | 5 | #include "v8.h" | |
| 6 | 6 | ||
| 7 | 7 | #include <fcntl.h> | |
@@ -117,7 +117,8 @@ namespace permission { | |||
| 117 | 117 | ||
| 118 | 118 | // allow = '*' | |
| 119 | 119 | // allow = '/tmp/,/home/example.js' | |
| 120 | - void FSPermission::Apply(const std::vector<std::string>& allow, | ||
| 120 | + void FSPermission::Apply(Environment* env, | ||
| 121 | + const std::vector<std::string>& allow, | ||
| 121 | 122 | PermissionScope scope) { | |
| 122 | 123 | for (const std::string& res : allow) { | |
| 123 | 124 | if (res == "*") { | |
@@ -130,7 +131,7 @@ void FSPermission::Apply(const std::vector<std::string>& allow, | |||
| 130 | 131 | } | |
| 131 | 132 | return; | |
| 132 | 133 | } | |
| 133 | - GrantAccess(scope, res); | ||
| 134 | + GrantAccess(scope, PathResolve(env, {res})); | ||
| 134 | 135 | } | |
| 135 | 136 | } | |
| 136 | 137 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments