diff --git a/lib/fs.js b/lib/fs.js index 2119554c0e7..570f014dcb5 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1546,7 +1546,8 @@ function lstat(path, options = { bigint: false }, callback) { callback = makeStatsCallback(callback); path = getValidatedPath(path); if (permission.isEnabled() && !permission.has('fs.read', path)) { - callback(new ERR_ACCESS_DENIED('Access to this API has been restricted', 'FileSystemRead', path)); + const resource = BufferIsBuffer(path) ? BufferToString(path) : path; + callback(new ERR_ACCESS_DENIED('Access to this API has been restricted', 'FileSystemRead', resource)); return; } @@ -1623,7 +1624,8 @@ function fstatSync(fd, options = { bigint: false }) { function lstatSync(path, options = { bigint: false, throwIfNoEntry: true }) { path = getValidatedPath(path); if (permission.isEnabled() && !permission.has('fs.read', path)) { - throw new ERR_ACCESS_DENIED('Access to this API has been restricted', 'FileSystemRead', path); + const resource = BufferIsBuffer(path) ? BufferToString(path) : path; + throw new ERR_ACCESS_DENIED('Access to this API has been restricted', 'FileSystemRead', resource); } const stats = binding.lstat( getValidatedPath(path), diff --git a/lib/internal/process/permission.js b/lib/internal/process/permission.js index f0d5f2b180b..7a6dd80d1d0 100644 --- a/lib/internal/process/permission.js +++ b/lib/internal/process/permission.js @@ -5,7 +5,9 @@ const { } = primordials; const permission = internalBinding('permission'); -const { validateString } = require('internal/validators'); +const { validateString, validateBuffer } = require('internal/validators'); +const { Buffer } = require('buffer'); +const { isBuffer } = Buffer; let experimentalPermission; @@ -22,7 +24,11 @@ module.exports = ObjectFreeze({ validateString(scope, 'scope'); if (reference != null) { // TODO: add support for WHATWG URLs and Uint8Arrays. - validateString(reference, 'reference'); + if (isBuffer(reference)) { + validateBuffer(reference, 'reference'); + } else { + validateString(reference, 'reference'); + } } return permission.has(scope, reference); diff --git a/test/fixtures/permission/fs-read.js b/test/fixtures/permission/fs-read.js index 0ce7d65b21b..29594ca8b5d 100644 --- a/test/fixtures/permission/fs-read.js +++ b/test/fixtures/permission/fs-read.js @@ -7,6 +7,7 @@ const fs = require('fs'); const path = require('path'); const blockedFile = process.env.BLOCKEDFILE; +const bufferBlockedFile = Buffer.from(process.env.BLOCKEDFILE); const blockedFileURL = new URL('file://' + process.env.BLOCKEDFILE); const blockedFolder = process.env.BLOCKEDFOLDER; const allowedFolder = process.env.ALLOWEDFOLDER; @@ -408,6 +409,11 @@ const regularFile = __filename; }, common.expectsError({ code: 'ERR_ACCESS_DENIED', })); + assert.throws(() => { + fs.lstatSync(bufferBlockedFile); + }, common.expectsError({ + code: 'ERR_ACCESS_DENIED', + })); // doesNotThrow fs.lstat(regularFile, (err) => { diff --git a/test/fixtures/permission/fs-traversal.js b/test/fixtures/permission/fs-traversal.js index 8f2e4c0fd55..764ae669252 100644 --- a/test/fixtures/permission/fs-traversal.js +++ b/test/fixtures/permission/fs-traversal.js @@ -69,6 +69,16 @@ const uint8ArrayTraversalPath = new TextEncoder().encode(traversalPath); })); } +{ + fs.lstat(bufferTraversalPath, common.expectsError({ + code: 'ERR_ACCESS_DENIED', + permission: 'FileSystemRead', + // lstat checks and throw on JS side. + // resource is only resolved on C++ (is_granted) + resource: bufferTraversalPath.toString(), + })); +} + { fs.readFile(uint8ArrayTraversalPath, common.expectsError({ code: 'ERR_ACCESS_DENIED', diff --git a/test/parallel/test-permission-has.js b/test/parallel/test-permission-has.js index f0fb582959f..3be45c5b2a4 100644 --- a/test/parallel/test-permission-has.js +++ b/test/parallel/test-permission-has.js @@ -21,3 +21,7 @@ const assert = require('assert'); message: 'The "reference" argument must be of type string. Received an instance of Object', })); } + +{ + assert.ok(!process.permission.has('FileSystemWrite', Buffer.from('reference'))); +}