mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
src,permission: add --allow-inspector ability
Refs: https://github.com/nodejs/node/issues/48534 PR-URL: https://github.com/nodejs/node/pull/59711 Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
This commit is contained in:
parent
ac131bdc01
commit
29738c7b42
|
|
@ -275,6 +275,36 @@ When passing a single flag with a comma a warning will be displayed.
|
||||||
|
|
||||||
Examples can be found in the [File System Permissions][] documentation.
|
Examples can be found in the [File System Permissions][] documentation.
|
||||||
|
|
||||||
|
### `--allow-inspector`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
> Stability: 1.0 - Early development
|
||||||
|
|
||||||
|
When using the [Permission Model][], the process will not be able to connect
|
||||||
|
through inspector protocol.
|
||||||
|
|
||||||
|
Attempts to do so will throw an `ERR_ACCESS_DENIED` unless the
|
||||||
|
user explicitly passes the `--allow-inspector` flag when starting Node.js.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { Session } = require('node:inspector/promises');
|
||||||
|
|
||||||
|
const session = new Session();
|
||||||
|
session.connect();
|
||||||
|
```
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ node --permission index.js
|
||||||
|
Error: connect ERR_ACCESS_DENIED Access to this API has been restricted. Use --allow-inspector to manage permissions.
|
||||||
|
code: 'ERR_ACCESS_DENIED',
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `--allow-net`
|
### `--allow-net`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
|
@ -3427,6 +3457,7 @@ one is included in the list below.
|
||||||
* `--allow-child-process`
|
* `--allow-child-process`
|
||||||
* `--allow-fs-read`
|
* `--allow-fs-read`
|
||||||
* `--allow-fs-write`
|
* `--allow-fs-write`
|
||||||
|
* `--allow-inspector`
|
||||||
* `--allow-net`
|
* `--allow-net`
|
||||||
* `--allow-wasi`
|
* `--allow-wasi`
|
||||||
* `--allow-worker`
|
* `--allow-worker`
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ flag.
|
||||||
When starting Node.js with `--permission`,
|
When starting Node.js with `--permission`,
|
||||||
the ability to access the file system through the `fs` module, access the network,
|
the ability to access the file system through the `fs` module, access the network,
|
||||||
spawn processes, use `node:worker_threads`, use native addons, use WASI, and
|
spawn processes, use `node:worker_threads`, use native addons, use WASI, and
|
||||||
enable the runtime inspector will be restricted.
|
enable the runtime inspector will be restricted (the listener for SIGUSR1 won't
|
||||||
|
be created).
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ node --permission index.js
|
$ node --permission index.js
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"allow-inspector": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"allow-net": {
|
"allow-net": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,9 @@ Allow using native addons when using the permission model.
|
||||||
.It Fl -allow-child-process
|
.It Fl -allow-child-process
|
||||||
Allow spawning process when using the permission model.
|
Allow spawning process when using the permission model.
|
||||||
.
|
.
|
||||||
|
.It Fl -allow-inspector
|
||||||
|
Allow inspector access when using the permission model.
|
||||||
|
.
|
||||||
.It Fl -allow-net
|
.It Fl -allow-net
|
||||||
Allow network access when using the permission model.
|
Allow network access when using the permission model.
|
||||||
.
|
.
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ module.exports = ObjectFreeze({
|
||||||
'--allow-addons',
|
'--allow-addons',
|
||||||
'--allow-child-process',
|
'--allow-child-process',
|
||||||
'--allow-net',
|
'--allow-net',
|
||||||
|
'--allow-inspector',
|
||||||
'--allow-wasi',
|
'--allow-wasi',
|
||||||
'--allow-worker',
|
'--allow-worker',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -580,6 +580,7 @@ function initializePermission() {
|
||||||
const warnFlags = [
|
const warnFlags = [
|
||||||
'--allow-addons',
|
'--allow-addons',
|
||||||
'--allow-child-process',
|
'--allow-child-process',
|
||||||
|
'--allow-inspector',
|
||||||
'--allow-wasi',
|
'--allow-wasi',
|
||||||
'--allow-worker',
|
'--allow-worker',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -912,8 +912,10 @@ Environment::Environment(IsolateData* isolate_data,
|
||||||
options_->allow_native_addons = false;
|
options_->allow_native_addons = false;
|
||||||
permission()->Apply(this, {"*"}, permission::PermissionScope::kAddon);
|
permission()->Apply(this, {"*"}, permission::PermissionScope::kAddon);
|
||||||
}
|
}
|
||||||
flags_ = flags_ | EnvironmentFlags::kNoCreateInspector;
|
if (!options_->allow_inspector) {
|
||||||
permission()->Apply(this, {"*"}, permission::PermissionScope::kInspector);
|
flags_ = flags_ | EnvironmentFlags::kNoCreateInspector;
|
||||||
|
permission()->Apply(this, {"*"}, permission::PermissionScope::kInspector);
|
||||||
|
}
|
||||||
if (!options_->allow_child_process) {
|
if (!options_->allow_child_process) {
|
||||||
permission()->Apply(
|
permission()->Apply(
|
||||||
this, {"*"}, permission::PermissionScope::kChildProcess);
|
this, {"*"}, permission::PermissionScope::kChildProcess);
|
||||||
|
|
|
||||||
|
|
@ -606,6 +606,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
|
||||||
"allow use of child process when any permissions are set",
|
"allow use of child process when any permissions are set",
|
||||||
&EnvironmentOptions::allow_child_process,
|
&EnvironmentOptions::allow_child_process,
|
||||||
kAllowedInEnvvar);
|
kAllowedInEnvvar);
|
||||||
|
AddOption("--allow-inspector",
|
||||||
|
"allow use of inspector when any permissions are set",
|
||||||
|
&EnvironmentOptions::allow_inspector,
|
||||||
|
kAllowedInEnvvar);
|
||||||
AddOption("--allow-net",
|
AddOption("--allow-net",
|
||||||
"allow use of network when any permissions are set",
|
"allow use of network when any permissions are set",
|
||||||
&EnvironmentOptions::allow_net,
|
&EnvironmentOptions::allow_net,
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ class EnvironmentOptions : public Options {
|
||||||
std::vector<std::string> allow_fs_read;
|
std::vector<std::string> allow_fs_read;
|
||||||
std::vector<std::string> allow_fs_write;
|
std::vector<std::string> allow_fs_write;
|
||||||
bool allow_addons = false;
|
bool allow_addons = false;
|
||||||
|
bool allow_inspector = false;
|
||||||
bool allow_child_process = false;
|
bool allow_child_process = false;
|
||||||
bool allow_net = false;
|
bool allow_net = false;
|
||||||
bool allow_wasi = false;
|
bool allow_wasi = false;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ namespace permission {
|
||||||
#define WORKER_THREADS_PERMISSIONS(V) \
|
#define WORKER_THREADS_PERMISSIONS(V) \
|
||||||
V(WorkerThreads, "worker", PermissionsRoot, "--allow-worker")
|
V(WorkerThreads, "worker", PermissionsRoot, "--allow-worker")
|
||||||
|
|
||||||
#define INSPECTOR_PERMISSIONS(V) V(Inspector, "inspector", PermissionsRoot, "")
|
#define INSPECTOR_PERMISSIONS(V) \
|
||||||
|
V(Inspector, "inspector", PermissionsRoot, "--allow-inspector")
|
||||||
|
|
||||||
#define NET_PERMISSIONS(V) V(Net, "net", PermissionsRoot, "--allow-net")
|
#define NET_PERMISSIONS(V) V(Net, "net", PermissionsRoot, "--allow-net")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -364,6 +364,9 @@ if (hasCrypto) {
|
||||||
knownGlobals.add(globalThis.SubtleCrypto);
|
knownGlobals.add(globalThis.SubtleCrypto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { Worker } = require('node:worker_threads');
|
||||||
|
knownGlobals.add(Worker);
|
||||||
|
|
||||||
function allowGlobals(...allowlist) {
|
function allowGlobals(...allowlist) {
|
||||||
for (const val of allowlist) {
|
for (const val of allowlist) {
|
||||||
knownGlobals.add(val);
|
knownGlobals.add(val);
|
||||||
|
|
|
||||||
55
test/parallel/test-permission-allow-inspector.js
Normal file
55
test/parallel/test-permission-allow-inspector.js
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Flags: --permission --allow-fs-read=* --allow-inspector
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
|
||||||
|
common.skipIfInspectorDisabled();
|
||||||
|
|
||||||
|
const { Session } = require('node:inspector/promises');
|
||||||
|
const assert = require('node:assert');
|
||||||
|
|
||||||
|
const session = new Session();
|
||||||
|
session.connect();
|
||||||
|
|
||||||
|
// Guarantee WorkerImpl doesn't gets bypassed
|
||||||
|
(async () => {
|
||||||
|
await session.post('Debugger.enable');
|
||||||
|
await session.post('Runtime.enable');
|
||||||
|
|
||||||
|
globalThis.Worker = require('node:worker_threads').Worker;
|
||||||
|
|
||||||
|
const { result: { objectId } } = await session.post('Runtime.evaluate', { expression: 'Worker' });
|
||||||
|
const { internalProperties } = await session.post('Runtime.getProperties', { objectId: objectId });
|
||||||
|
const {
|
||||||
|
value: {
|
||||||
|
value: { scriptId }
|
||||||
|
}
|
||||||
|
} = internalProperties.filter((prop) => prop.name === '[[FunctionLocation]]')[0];
|
||||||
|
const { scriptSource } = await session.post('Debugger.getScriptSource', { scriptId });
|
||||||
|
|
||||||
|
const lineNumber = scriptSource.substring(0, scriptSource.indexOf('new WorkerImpl')).split('\n').length;
|
||||||
|
|
||||||
|
// Attempt to bypass it based on https://hackerone.com/reports/1962701
|
||||||
|
await session.post('Debugger.setBreakpointByUrl', {
|
||||||
|
lineNumber: lineNumber,
|
||||||
|
url: 'node:internal/worker',
|
||||||
|
columnNumber: 0,
|
||||||
|
condition: '((isInternal = true),false)'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.throws(() => {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
new Worker(`
|
||||||
|
const child_process = require("node:child_process");
|
||||||
|
console.log(child_process.execSync("ls -l").toString());
|
||||||
|
|
||||||
|
console.log(require("fs").readFileSync("/etc/passwd").toString())
|
||||||
|
`, {
|
||||||
|
eval: true,
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
message: 'Access to this API has been restricted. Use --allow-worker to manage permissions.',
|
||||||
|
code: 'ERR_ACCESS_DENIED',
|
||||||
|
permission: 'WorkerThreads'
|
||||||
|
});
|
||||||
|
})().then(common.mustCall());
|
||||||
|
|
@ -22,7 +22,7 @@ if (!common.hasCrypto)
|
||||||
const session = new Session();
|
const session = new Session();
|
||||||
session.connect();
|
session.connect();
|
||||||
}, common.expectsError({
|
}, common.expectsError({
|
||||||
message: 'Access to this API has been restricted. ',
|
message: 'Access to this API has been restricted. Use --allow-inspector to manage permissions.',
|
||||||
code: 'ERR_ACCESS_DENIED',
|
code: 'ERR_ACCESS_DENIED',
|
||||||
permission: 'Inspector',
|
permission: 'Inspector',
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ const assert = require('assert');
|
||||||
const warnFlags = [
|
const warnFlags = [
|
||||||
'--allow-addons',
|
'--allow-addons',
|
||||||
'--allow-child-process',
|
'--allow-child-process',
|
||||||
|
'--allow-inspector',
|
||||||
'--allow-wasi',
|
'--allow-wasi',
|
||||||
'--allow-worker',
|
'--allow-worker',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user