mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 16:34:00 +01:00
freeze: deny Windows link targets relative to a drive or its root (#3623)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
a5ad761f5f
commit
5a6547c552
2 files changed
+23
-4
No files matched your search
@@ -233,9 +233,10 @@ esac
|
||||
# POSIX file name. On a POSIX host a Windows path names no local file,
|
||||
# so it is resolved as text and no local symlink is followed.
|
||||
# Returns 1 for a symlink loop, a chain over 40 links, an unreadable or
|
||||
# line-broken link, link targets that add up past 8192 characters with the
|
||||
# path (the walk is quadratic, so its total input stays bounded), or an
|
||||
# unplaceable Windows name; the caller fails closed.
|
||||
# line-broken link, a Windows link target relative to a drive or its root,
|
||||
# link targets that add up past 8192 characters with the path (the walk is
|
||||
# quadratic, so its total input stays bounded), or an unplaceable Windows
|
||||
# name; the caller fails closed.
|
||||
_resolve_path() {
|
||||
local _rem="$1" _win="${3:-0}" _lead="" _cur="" _n=0 _min=0 _reroot=1
|
||||
local _part _tgt _p _tail="" _hops=0 _probe=1 _budget="${#1}"
|
||||
@@ -286,6 +287,7 @@ _resolve_path() {
|
||||
_tgt="${_tgt%x}"; _tgt="${_tgt%"$_FREEZE_NL"}"
|
||||
case "$_tgt" in ''|*"$_FREEZE_NL"*|*"$_FREEZE_CR"*) return 1 ;; esac
|
||||
if [ "$_win" = 1 ]; then
|
||||
case "$_tgt" in [A-Za-z]:|[A-Za-z]:[!\\/]*|\\|\\[!\\]*) return 1 ;; esac
|
||||
gstack_hook_normalize_path "$_tgt"
|
||||
_tgt="$GSTACK_HOOK_PATH"
|
||||
fi
|
||||
@@ -319,7 +321,7 @@ _resolve_path() {
|
||||
printf '%s' "$GSTACK_HOOK_PATH"
|
||||
}
|
||||
|
||||
_FREEZE_WHY="a symlink loop, a chain over 40 links, a path and link targets over 8192 characters in all, an unreadable link, or a Windows name that cannot be placed"
|
||||
_FREEZE_WHY="a symlink loop, a chain over 40 links, a path and link targets over 8192 characters in all, an unreadable link, a Windows link target relative to a drive or its root, or a Windows name that cannot be placed"
|
||||
FREEZE_DIR_RAW="$FREEZE_DIR"
|
||||
FREEZE_DIR=$(_resolve_path "$FREEZE_DIR_RAW" physical "$FREEZE_DIR_WIN") || _freeze_unresolved "the freeze boundary $FREEZE_DIR_RAW" "$_FREEZE_WHY"
|
||||
# Hosts disagree on '<link>/..': the OS means the target's parent, a lexical
|
||||
|
||||
@@ -1626,6 +1626,23 @@ describe('check-freeze.sh', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// Windows reads a link target of '\\x' against the link's drive root and
|
||||
// 'C:x' against drive C's own working directory; normalized as /x or C:/x,
|
||||
// either read as inside while the write landed elsewhere.
|
||||
test.skipIf(process.platform === 'win32')('Windows bash: a link target relative to a drive or its root denies, fail closed', () => {
|
||||
withTree(({ home, src }) => {
|
||||
fs.symlinkSync(src.split('/').join('\\'), path.join(src, 'rootrel'));
|
||||
fs.symlinkSync('C:x', path.join(src, 'driverel'));
|
||||
fs.symlinkSync('\\', path.join(src, 'bare'));
|
||||
fs.mkdirSync(path.join(src, 'real'));
|
||||
fs.symlinkSync(path.join(src, 'real'), path.join(src, 'fwd'));
|
||||
expect(decideOnWindowsBash(src, src + '/rootrel/x.ts', home, src)).toBe('deny');
|
||||
expect(decideOnWindowsBash(src, src + '/driverel/x.ts', home, src)).toBe('deny');
|
||||
expect(decideOnWindowsBash(src, src + '/bare' + src + '/x.ts', home, src)).toBe('deny');
|
||||
expect(decideOnWindowsBash(src, src + '/fwd/x.ts', home, src)).toBe('allow');
|
||||
});
|
||||
});
|
||||
|
||||
// On POSIX '\\' is a filename character, so a name that spells '..' with
|
||||
// backslashes is one directory, not a way back into the boundary.
|
||||
test.skipIf(process.platform === 'win32')('a POSIX backslash name that spells dotdot never counts as inside', () => {
|
||||
|
||||
Reference in new issue
Block a user