GeezerVison is showing github.com — permission: do not create symlinks if target is relative · nodejs/node@076dc75
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/fs.js +22Lines changed: 22 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -58,6 +58,7 @@ const { | 58 | 58 | } = constants; | 59 | 59 |
| 60 | 60 | const pathModule = require('path'); | | 61 | +const { isAbsolute } = pathModule; | 61 | 62 | const { isArrayBufferView } = require('internal/util/types'); | 62 | 63 |
| 63 | 64 | const binding = internalBinding('fs'); | @@ -68,6 +69,7 @@ const { Buffer } = require('buffer'); | 68 | 69 | const { | 69 | 70 | aggregateTwoErrors, | 70 | 71 | codes: { | | 72 | + ERR_ACCESS_DENIED, | 71 | 73 | ERR_FS_FILE_TOO_LARGE, | 72 | 74 | ERR_INVALID_ARG_VALUE, | 73 | 75 | }, | @@ -143,6 +145,8 @@ const { | 143 | 145 | kValidateObjectAllowNullable, | 144 | 146 | } = require('internal/validators'); | 145 | 147 |
| | 148 | +const permission = require('internal/process/permission'); | | 149 | + | 146 | 150 | let truncateWarn = true; | 147 | 151 | let fs; | 148 | 152 |
| @@ -1740,6 +1744,15 @@ function symlink(target, path, type_, callback_) { | 1740 | 1744 | const type = (typeof type_ === 'string' ? type_ : null); | 1741 | 1745 | const callback = makeCallback(arguments[arguments.length - 1]); | 1742 | 1746 |
| | 1747 | + if (permission.isEnabled()) { | | 1748 | + // The permission model's security guarantees fall apart in the presence of | | 1749 | + // relative symbolic links. Thus, we have to prevent their creation. | | 1750 | + if (typeof target !== 'string' || !isAbsolute(toPathIfFileURL(target))) { | | 1751 | + callback(new ERR_ACCESS_DENIED('relative symbolic link target')); | | 1752 | + return; | | 1753 | + } | | 1754 | + } | | 1755 | + | 1743 | 1756 | target = getValidatedPath(target, 'target'); | 1744 | 1757 | path = getValidatedPath(path); | 1745 | 1758 |
| @@ -1796,6 +1809,15 @@ function symlinkSync(target, path, type) { | 1796 | 1809 | type = 'dir'; | 1797 | 1810 | } | 1798 | 1811 | } | | 1812 | + | | 1813 | + if (permission.isEnabled()) { | | 1814 | + // The permission model's security guarantees fall apart in the presence of | | 1815 | + // relative symbolic links. Thus, we have to prevent their creation. | | 1816 | + if (typeof target !== 'string' || !isAbsolute(toPathIfFileURL(target))) { | | 1817 | + throw new ERR_ACCESS_DENIED('relative symbolic link target'); | | 1818 | + } | | 1819 | + } | | 1820 | + | 1799 | 1821 | target = getValidatedPath(target, 'target'); | 1800 | 1822 | path = getValidatedPath(path); | 1801 | 1823 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/fs/promises.js +14Lines changed: 14 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -33,6 +33,7 @@ const { Buffer } = require('buffer'); | 33 | 33 |
| 34 | 34 | const { | 35 | 35 | codes: { | | 36 | + ERR_ACCESS_DENIED, | 36 | 37 | ERR_FS_FILE_TOO_LARGE, | 37 | 38 | ERR_INVALID_ARG_VALUE, | 38 | 39 | ERR_INVALID_STATE, | @@ -85,6 +86,8 @@ const { | 85 | 86 | kValidateObjectAllowNullable, | 86 | 87 | } = require('internal/validators'); | 87 | 88 | const pathModule = require('path'); | | 89 | +const { isAbsolute } = pathModule; | | 90 | +const { toPathIfFileURL } = require('internal/url'); | 88 | 91 | const { | 89 | 92 | kEmptyObject, | 90 | 93 | lazyDOMException, | @@ -97,6 +100,8 @@ const nonNativeWatcher = require('internal/fs/recursive_watch'); | 97 | 100 | const { isIterable } = require('internal/streams/utils'); | 98 | 101 | const assert = require('internal/assert'); | 99 | 102 |
| | 103 | +const permission = require('internal/process/permission'); | | 104 | + | 100 | 105 | const kHandle = Symbol('kHandle'); | 101 | 106 | const kFd = Symbol('kFd'); | 102 | 107 | const kRefs = Symbol('kRefs'); | @@ -883,6 +888,15 @@ async function symlink(target, path, type_) { | 883 | 888 | type = 'file'; | 884 | 889 | } | 885 | 890 | } | | 891 | + | | 892 | + if (permission.isEnabled()) { | | 893 | + // The permission model's security guarantees fall apart in the presence of | | 894 | + // relative symbolic links. Thus, we have to prevent their creation. | | 895 | + if (typeof target !== 'string' || !isAbsolute(toPathIfFileURL(target))) { | | 896 | + throw new ERR_ACCESS_DENIED('relative symbolic link target'); | | 897 | + } | | 898 | + } | | 899 | + | 886 | 900 | target = getValidatedPath(target, 'target'); | 887 | 901 | path = getValidatedPath(path); | 888 | 902 | return binding.symlink(preprocessSymlinkDestination(target, type, path), | |
Collapse file Copy file name to clipboard +27Lines changed: 27 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +// Flags: --experimental-permission --allow-fs-read=* --allow-fs-write=* | | 2 | +'use strict'; | | 3 | + | | 4 | +const common = require('../common'); | | 5 | +common.skipIfWorker(); | | 6 | + | | 7 | +const assert = require('assert'); | | 8 | +const { symlinkSync, symlink, promises: { symlink: symlinkAsync } } = require('fs'); | | 9 | + | | 10 | +const error = { | | 11 | + code: 'ERR_ACCESS_DENIED', | | 12 | + message: /relative symbolic link target/, | | 13 | +}; | | 14 | + | | 15 | +for (const targetString of ['a', './b/c', '../d', 'e/../f', 'C:drive-relative', 'ntfs:alternate']) { | | 16 | + for (const target of [targetString, Buffer.from(targetString)]) { | | 17 | + for (const path of [__filename, __dirname, process.execPath]) { | | 18 | + assert.throws(() => symlinkSync(target, path), error); | | 19 | + symlink(target, path, common.mustCall((err) => { | | 20 | + assert(err); | | 21 | + assert.strictEqual(err.code, error.code); | | 22 | + assert.match(err.message, error.message); | | 23 | + })); | | 24 | + assert.rejects(() => symlinkAsync(target, path), error).then(common.mustCall()); | | 25 | + } | | 26 | + } | | 27 | +} |
|