mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
Enable node:vfs by default. --no-experimental-vfs disables node:vfs exposure and --vfs-load. Assisted-by: pi Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: https://github.com/nodejs/node/pull/66318 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it>
114 lines
4.0 KiB
JavaScript
114 lines
4.0 KiB
JavaScript
// Flags: --expose-internals
|
|
'use strict';
|
|
|
|
// Loading an addon from bytes materializes them into an image in the temporary
|
|
// directory, so dlopenBinary() requires file-system write access on top of the
|
|
// addon permission every dlopen already needs. Granting only one of the two is
|
|
// not enough.
|
|
|
|
const common = require('../common');
|
|
const assert = require('assert');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { spawnSync } = require('child_process');
|
|
|
|
const addonPath = path.join(
|
|
__dirname, '..', 'addons', 'hello-world', 'build', 'Release', 'binding.node');
|
|
if (!fs.existsSync(addonPath)) common.skip('the hello-world addon is not built');
|
|
|
|
// Loads the addon from bytes at a path that does not exist on disk, as an
|
|
// addon served by a virtual file system would be, and reports what happened.
|
|
const child = `
|
|
const { internalBinding } = require('internal/test/binding');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
const { dlopenBinary } = internalBinding('process_methods');
|
|
const bytes = fs.readFileSync(${JSON.stringify(addonPath)});
|
|
const target = path.join(os.tmpdir(), 'nonexistent-vfs-dir', 'binding.node');
|
|
const m = { exports: {} };
|
|
try {
|
|
dlopenBinary(m, target, undefined, bytes);
|
|
console.log('LOADED', m.exports.hello());
|
|
} catch (err) {
|
|
console.log('DENIED', err.code, err.permission ?? '');
|
|
}
|
|
`;
|
|
|
|
function run(...permissions) {
|
|
return spawnSync(
|
|
process.execPath,
|
|
['--expose-internals', '--permission', '--allow-fs-read=*',
|
|
...permissions, '-e', child],
|
|
{ encoding: 'utf8' });
|
|
}
|
|
|
|
// Both permissions granted: the addon loads.
|
|
{
|
|
const res = run('--allow-addons', '--allow-fs-write=*');
|
|
assert.strictEqual(res.status, 0, res.stderr);
|
|
assert.match(res.stdout, /LOADED world/);
|
|
}
|
|
|
|
// Addons allowed but no write access: refused by the file-system check, so the
|
|
// bytes are never materialized.
|
|
{
|
|
const res = run('--allow-addons');
|
|
assert.strictEqual(res.status, 0, res.stderr);
|
|
assert.match(res.stdout, /DENIED ERR_ACCESS_DENIED FileSystemWrite/);
|
|
}
|
|
|
|
// Write access but addons disallowed: refused before the bytes are looked at,
|
|
// the same as any other dlopen under the permission model.
|
|
{
|
|
const res = run('--allow-fs-write=*');
|
|
assert.strictEqual(res.status, 0, res.stderr);
|
|
assert.match(res.stdout, /DENIED ERR_DLOPEN_DISABLED/);
|
|
}
|
|
|
|
// Without the permission model neither check applies.
|
|
{
|
|
const res = spawnSync(process.execPath, ['--expose-internals', '-e', child],
|
|
{ encoding: 'utf8' });
|
|
assert.strictEqual(res.status, 0, res.stderr);
|
|
assert.match(res.stdout, /LOADED world/);
|
|
}
|
|
|
|
// The same, reached the way a program actually gets here: an addon inside a
|
|
// mounted VFS. Mounting one under the permission model needs --allow-fs-vfs.
|
|
{
|
|
const mounted = `
|
|
const fs = require('fs');
|
|
const vfs = require('node:vfs');
|
|
const myVfs = vfs.create();
|
|
myVfs.writeFileSync('/binding.node',
|
|
fs.readFileSync(${JSON.stringify(addonPath)}));
|
|
const mountPoint = myVfs.mount();
|
|
try {
|
|
console.log('LOADED', require(mountPoint + '/binding.node').hello());
|
|
} catch (err) {
|
|
console.log('DENIED', err.code, err.permission ?? '');
|
|
}
|
|
`;
|
|
const vfsRun = (...permissions) => spawnSync(
|
|
process.execPath,
|
|
['--permission', '--allow-fs-read=*',
|
|
...permissions, '-e', mounted],
|
|
{ encoding: 'utf8' });
|
|
|
|
const ok = vfsRun('--allow-fs-vfs', '--allow-addons', '--allow-fs-write=*');
|
|
assert.strictEqual(ok.status, 0, ok.stderr);
|
|
assert.match(ok.stdout, /LOADED world/);
|
|
|
|
// Mounting itself is refused without --allow-fs-vfs.
|
|
const noVfs = vfsRun('--allow-addons', '--allow-fs-write=*');
|
|
assert.notStrictEqual(noVfs.status, 0);
|
|
assert.match(noVfs.stderr, /ERR_INVALID_STATE/);
|
|
assert.match(noVfs.stderr, /--allow-fs-vfs/);
|
|
|
|
// Mounted, addons allowed, but no write access: the addon is refused.
|
|
const noWrite = vfsRun('--allow-fs-vfs', '--allow-addons');
|
|
assert.strictEqual(noWrite.status, 0, noWrite.stderr);
|
|
assert.match(noWrite.stdout, /DENIED ERR_ACCESS_DENIED FileSystemWrite/);
|
|
}
|