Skip to content

Ensure ntpath.realpath() result is a final, normalized pathname.#110495

@moonsikpark

Description

@moonsikpark

Bug report

Bug description:

Note that _readlink_deep() does nothing to ensure that the result is a final, normalized pathname. It just tries to keep reading symlinks until the target isn't a symlink or access/reading fails in a manner that's allowed. If it succeeds, the resulting pathname may include any number of symlinks, mount points, and short names. _getfinalpathname_nonstrict() should instead pass both the pathname and the seen set into _readlink_deep(). If it succeeds, then add the resulting pathname to the set, and continue the loop to try to get a final, normalized pathname.

Originally posted by @eryksun in #110298 (comment)

I was able to reproduce this issue. Run the following code block with Administrator privileges in Windows:

mkdir C:\testdir mkdir C:\testdir\real echo 1 > C:\testdir\real\file.txt icacls C:\testdir\real\file.txt /deny *S-1-5-32-545:(S) mklink /d C:\testdir\symlink1 C:\testdir\real mklink /d C:\testdir\symlink2 C:\testdir\symlink1 mklink C:\testdir\symlink2\filelink.txt C:\testdir\symlink1\file.txt python -c "import ntpath; print(ntpath.realpath('C:\\testdir\\symlink2\\filelink.txt'))" REM Cleanup icacls C:\testdir\real\file.txt /grant *S-1-5-32-545:(S) rmdir C:\testdir /s /q

Expected output:

C:\testdir\real\file.txt 

Actual output:

C:\testdir\symlink1\file.txt 

This happens because _getfinalpathname_nonstrict() returns the result of _readlink_deep() if the return value is different from the input.

cpython/Lib/ntpath.py

Lines 680 to 686 in 92ca90b

try:
# The OS could not resolve this path fully, so we attempt
# to follow the link ourselves. If we succeed, join the tail
# and return.
new_path=_readlink_deep(path)
ifnew_path!=path:
returnjoin(new_path, tail) iftailelsenew_path

However, because _readlink_deep() does not ensure that it's result is a final, normalized pathname, ntpath.realpath() result is not ensured to be a final, normalized pathname.

I'll try to come up with a patch. @eryksun, if you have any further discussions or comments on how this should be fixed, please let me know in the comments.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Windows

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    OS-windowstype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions