mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
358ff748ea
PR-URL: https://github.com/nodejs/node/pull/54104 Fixes: https://github.com/nodejs/node/issues/54100 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
128 lines
3.8 KiB
JavaScript
128 lines
3.8 KiB
JavaScript
'use strict'
|
|
|
|
const common = require('../../common');
|
|
|
|
const assert = require('assert');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const { resolve } = path;
|
|
// This should not affect how the permission model resolves paths.
|
|
try {
|
|
path.resolve = (s) => s;
|
|
assert.fail('should not be called');
|
|
} catch {}
|
|
|
|
const blockedFolder = process.env.BLOCKEDFOLDER;
|
|
const allowedFolder = process.env.ALLOWEDFOLDER;
|
|
const traversalPath = allowedFolder + '/../file.md';
|
|
const traversalFolderPath = allowedFolder + '/../folder';
|
|
const bufferTraversalPath = Buffer.from(traversalPath);
|
|
const uint8ArrayTraversalPath = new TextEncoder().encode(traversalPath);
|
|
|
|
{
|
|
assert.ok(process.permission.has('fs.read', allowedFolder));
|
|
assert.ok(process.permission.has('fs.write', allowedFolder));
|
|
assert.ok(!process.permission.has('fs.read', blockedFolder));
|
|
assert.ok(!process.permission.has('fs.write', blockedFolder));
|
|
}
|
|
|
|
{
|
|
fs.writeFile(traversalPath, 'test', common.expectsError({
|
|
code: 'ERR_ACCESS_DENIED',
|
|
permission: 'FileSystemWrite',
|
|
resource: path.toNamespacedPath(traversalPath),
|
|
}));
|
|
}
|
|
|
|
{
|
|
fs.readFile(traversalPath, common.expectsError({
|
|
code: 'ERR_ACCESS_DENIED',
|
|
permission: 'FileSystemRead',
|
|
resource: path.toNamespacedPath(traversalPath),
|
|
}));
|
|
}
|
|
|
|
{
|
|
assert.throws(() => {
|
|
fs.mkdtempSync(traversalFolderPath);
|
|
}, common.expectsError({
|
|
code: 'ERR_ACCESS_DENIED',
|
|
permission: 'FileSystemWrite',
|
|
resource: traversalFolderPath + 'XXXXXX',
|
|
}));
|
|
}
|
|
|
|
{
|
|
fs.mkdtemp(traversalFolderPath, common.expectsError({
|
|
code: 'ERR_ACCESS_DENIED',
|
|
permission: 'FileSystemWrite',
|
|
resource: traversalFolderPath + 'XXXXXX',
|
|
}));
|
|
}
|
|
|
|
{
|
|
fs.readFile(bufferTraversalPath, common.expectsError({
|
|
code: 'ERR_ACCESS_DENIED',
|
|
permission: 'FileSystemRead',
|
|
resource: path.toNamespacedPath(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',
|
|
permission: 'FileSystemRead',
|
|
resource: path.toNamespacedPath(traversalPath),
|
|
}));
|
|
}
|
|
|
|
// Monkey-patching Buffer internals should also not allow path traversal.
|
|
{
|
|
const extraChars = '.'.repeat(40);
|
|
const traversalPathWithExtraChars = traversalPath + extraChars;
|
|
const traversalPathWithExtraBytes = Buffer.from(traversalPathWithExtraChars);
|
|
|
|
Buffer.prototype.utf8Write = ((w) => function(str, ...args) {
|
|
assert.strictEqual(str, resolve(traversalPath) + extraChars);
|
|
return w.apply(this, [traversalPath, ...args]);
|
|
})(Buffer.prototype.utf8Write);
|
|
|
|
// Sanity check (remove if the internals of Buffer.from change):
|
|
// The custom implementation of utf8Write should cause Buffer.from() to encode
|
|
// traversalPath instead of the sanitized output of resolve().
|
|
assert.strictEqual(Buffer.from(resolve(traversalPathWithExtraChars)).toString(), traversalPath);
|
|
|
|
assert.throws(() => {
|
|
fs.readFileSync(traversalPathWithExtraBytes);
|
|
}, common.expectsError({
|
|
code: 'ERR_ACCESS_DENIED',
|
|
permission: 'FileSystemRead',
|
|
resource: path.toNamespacedPath(traversalPathWithExtraChars),
|
|
}));
|
|
|
|
assert.throws(() => {
|
|
fs.readFileSync(new TextEncoder().encode(traversalPathWithExtraBytes.toString()));
|
|
}, common.expectsError({
|
|
code: 'ERR_ACCESS_DENIED',
|
|
permission: 'FileSystemRead',
|
|
resource: path.toNamespacedPath(traversalPathWithExtraChars),
|
|
}));
|
|
}
|
|
|
|
{
|
|
assert.ok(!process.permission.has('fs.read', traversalPath));
|
|
assert.ok(!process.permission.has('fs.write', traversalPath));
|
|
assert.ok(!process.permission.has('fs.read', traversalFolderPath));
|
|
assert.ok(!process.permission.has('fs.write', traversalFolderPath));
|
|
} |