Skip to content
Merged
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
24 changes: 12 additions & 12 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ process.
<!-- YAML
added: v20.0.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/58579
description: Entrypoints of your application are allowed to be read implicitly.
- version:
- v23.5.0
- v22.13.0
Expand All @@ -215,23 +218,20 @@ The valid arguments for the `--allow-fs-read` flag are:

Examples can be found in the [File System Permissions][] documentation.

The initializer module also needs to be allowed. Consider the following example:
The initializer module and custom `--require` modules has a implicit
read permission.

```console
$ node --permission index.js

Error: Access to this API has been restricted
at node:internal/main/run_main_module:23:47 {
code: 'ERR_ACCESS_DENIED',
permission: 'FileSystemRead',
resource: '/Users/rafaelgss/repos/os/node/index.js'
}
$ node --permission -r custom-require.js -r custom-require-2.js index.js
```

The process needs to have access to the `index.js` module:
* The `custom-require.js`, `custom-require-2.js`, and `index.js` will be
by default in the allowed read list.

```bash
node --permission --allow-fs-read=/path/to/index.js index.js
```js
process.has('fs.read', 'index.js'); // true
process.has('fs.read', 'custom-require.js'); // true
process.has('fs.read', 'custom-require-2.js'); // true
```

### `--allow-fs-write`
Expand Down
17 changes: 17 additions & 0 deletions doc/api/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,23 @@ $ node --permission --allow-fs-read=* --allow-fs-write=* index.js
Hello world!
```

By default the entrypoints of your application are included
in the allowed file system read list. For example:

```console
$ node --permission index.js
```

* `index.js` will be included in the allowed file system read list

```console
$ node -r /path/to/custom-require.js --permission index.js.
```

* `/path/to/custom-require.js` will be included in the allowed file system read
list.
* `index.js` will be included in the allowed file system read list.

The valid arguments for both flags are:

* `*` - To allow all `FileSystemRead` or `FileSystemWrite` operations,
Expand Down
19 changes: 19 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,25 @@ Environment::Environment(IsolateData* isolate_data,
permission()->Apply(this, {"*"}, permission::PermissionScope::kWASI);
}

// Implicit allow entrypoint to kFileSystemRead
if (!options_->has_eval_string && !options_->force_repl) {
std::string first_argv;
if (argv_.size() > 1) {
first_argv = argv_[1];
}

// Also implicit allow preloaded modules to kFileSystemRead
if (!options_->preload_cjs_modules.empty()) {
for (const std::string& mod : options_->preload_cjs_modules) {
options_->allow_fs_read.push_back(mod);
}
}

if (first_argv != "inspect") {
options_->allow_fs_read.push_back(first_argv);
}
}

if (!options_->allow_fs_read.empty()) {
permission()->Apply(this,
options_->allow_fs_read,
Expand Down
15 changes: 15 additions & 0 deletions test/fixtures/permission/fs-read-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const fs = require('node:fs')
const path = require('node:path')
const assert = require('node:assert');

{
fs.readFileSync(__filename);
console.log('Read its own contents') // Should not throw
}
{
const simpleLoaderPath = path.join(__dirname, 'simple-loader.js');
fs.readFile(simpleLoaderPath, (err) => {
assert.ok(err.code, 'ERR_ACCESS_DENIED');
assert.ok(err.permission, 'FileSystemRead');
}); // Should throw ERR_ACCESS_DENIED
}
1 change: 1 addition & 0 deletions test/fixtures/permission/hello-world.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello world')
3 changes: 3 additions & 0 deletions test/fixtures/permission/simple-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Simulate a regular loading without fs operations
// but with access to Node core modules
require('node:fs')
38 changes: 38 additions & 0 deletions test/parallel/test-permission-fs-read-entrypoint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Flags: --permission --allow-fs-read=* --allow-fs-write=* --allow-child-process
'use strict';

const common = require('../common');
const { isMainThread } = require('worker_threads');

if (!isMainThread) {
common.skip('This test only works on a main thread');
}

if (!common.hasCrypto) {
common.skip('no crypto');
}

const assert = require('assert');
const fixtures = require('../common/fixtures');
const { spawnSync } = require('child_process');

const file = fixtures.path('permission', 'hello-world.js');
const simpleLoader = fixtures.path('permission', 'simple-loader.js');
const fsReadLoader = fixtures.path('permission', 'fs-read-loader.js');

[
'',
simpleLoader,
fsReadLoader,
].forEach((arg0) => {
const { status, stderr } = spawnSync(
process.execPath,
[
arg0 !== '' ? '-r' : '',
arg0,
'--permission',
file,
],
);
assert.strictEqual(status, 0, `${arg0} Error: ${stderr.toString()}`);
});
6 changes: 5 additions & 1 deletion test/parallel/test-permission-fs-read.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ const commonPath = path.join(__filename, '../../common');
const { status, stderr } = spawnSync(
process.execPath,
[
'--permission', `--allow-fs-read=${file}`, `--allow-fs-read=${commonPathWildcard}`, file,
'--permission',
// Do not uncomment this line
// `--allow-fs-read=${file}`,
`--allow-fs-read=${commonPathWildcard}`,
file,
],
{
env: {
Expand Down
Loading