Skip to content

Commit

Permalink
lib,permission: support fs.lstat
Browse files Browse the repository at this point in the history
PR-URL: nodejs-private/node-private#486
Fixes: https://hackerone.com/bugs?subject=nodejs&report_id=2145862
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
CVE-ID: CVE-2024-22018
  • Loading branch information
RafaelGSS committed Jul 8, 2024
1 parent 39f2070 commit b9289a6
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 6 deletions.
8 changes: 8 additions & 0 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,10 @@ 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));
return;
}

const req = new FSReqCallback(options.bigint);
req.oncomplete = callback;
Expand Down Expand Up @@ -1622,6 +1626,10 @@ function fstatSync(fd, options = { bigint: false }) {
* @returns {Stats | undefined}
*/
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 stats = binding.lstat(
getValidatedPath(path),
options.bigint,
Expand Down
6 changes: 5 additions & 1 deletion lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,11 @@ module.exports = {
// Note: Node.js specific errors must begin with the prefix ERR_

E('ERR_ACCESS_DENIED',
'Access to this API has been restricted. Permission: %s',
function(msg, permission = '', resource = '') {
this.permission = permission;
this.resource = resource;
return msg;
},
Error);
E('ERR_AMBIGUOUS_ARGUMENT', 'The "%s" argument is ambiguous. %s', TypeError);
E('ERR_ARG_NOT_ITERABLE', '%s must be iterable', TypeError);
Expand Down
29 changes: 24 additions & 5 deletions test/fixtures/permission/fs-read.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,23 +161,23 @@ const regularFile = __filename;
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
permission: 'FileSystemRead',
// cpSync calls statSync before reading blockedFile
resource: path.toNamespacedPath(blockedFolder),
// cpSync calls lstatSync before reading blockedFile
resource: blockedFile,
}));
assert.throws(() => {
fs.cpSync(blockedFileURL, path.join(blockedFolder, 'any-other-file'));
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
permission: 'FileSystemRead',
// cpSync calls statSync before reading blockedFile
resource: path.toNamespacedPath(blockedFolder),
// cpSync calls lstatSync before reading blockedFile
resource: blockedFile,
}));
assert.throws(() => {
fs.cpSync(blockedFile, path.join(__dirname, 'any-other-file'));
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
permission: 'FileSystemRead',
resource: path.toNamespacedPath(__dirname),
resource: blockedFile,
}));
}

Expand Down Expand Up @@ -396,4 +396,23 @@ const regularFile = __filename;
permission: 'FileSystemRead',
resource: blockedFolder,
}));
}

// fs.lstat
{
assert.throws(() => {
fs.lstatSync(blockedFile);
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
}));
assert.throws(() => {
fs.lstatSync(path.join(blockedFolder, 'anyfile'));
}, common.expectsError({
code: 'ERR_ACCESS_DENIED',
}));

// doesNotThrow
fs.lstat(regularFile, (err) => {
assert.ifError(err);
});
}

0 comments on commit b9289a6

Please sign in to comment.