Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

posixpath.realpath('secretlink') raises #118447

Closed
nineteendo opened this issue Apr 30, 2024 · 8 comments
Closed

posixpath.realpath('secretlink') raises #118447

nineteendo opened this issue Apr 30, 2024 · 8 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@nineteendo
Copy link
Contributor

nineteendo commented Apr 30, 2024

Bug report

Bug description:

GNU coreutils realpath -m doesn't raise an error for secret symlinks (no read permission):

wannes@Stefans-iMac dirs % sudo ls -l secret-symlink
l---------  1 wannes  staff  44 Jun 30  2023 secret-symlink -> /Users/wannes/path-picker/link-test/dirs/dir
wannes@Stefans-iMac dirs % grealpath -m secret-symlink
/Users/wannes/path-picker/link-test/dirs/secret-symlink

But posixpath.realpath() does:

>>> import posixpath
>>> posixpath.realpath("secret-symlink")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<frozen posixpath>", line 435, in realpath
  File "<frozen posixpath>", line 495, in _joinrealpath
PermissionError: [Errno 13] Permission denied: 'secret-symlink'

CPython versions tested on:

3.12

Operating systems tested on:

macOS

Linked PRs

@nineteendo nineteendo added the type-bug An unexpected behavior, bug, or error label Apr 30, 2024
@eryksun
Copy link
Contributor

eryksun commented Apr 30, 2024

Setting permissions on a symlink is a BSD (including macOS) feature. Linux doesn't allow it. Testing this should be limited to platforms with os.chmod in os.supports_follow_symlinks.

@nineteendo
Copy link
Contributor Author

Upon closer inspection, this is a bug in coreutils:

wannes@Stefans-iMac dirs % sudo ls -l secret-recursive-symlink
l---------  1 wannes  staff  40 Jun 30  2023 secret-recursive-symlink -> /Users/wannes/path-picker/link-test/dirs
wannes@Stefans-iMac dirs % sudo realpath secret-recursive-symlink/..
/Users/wannes/path-picker/link-test
wannes@Stefans-iMac dirs % grealpath -m secret-recursive-symlink/..
/Users/wannes/path-picker/link-test/dirs

@nineteendo nineteendo closed this as not planned Won't fix, can't repro, duplicate, stale May 2, 2024
@barneygale
Copy link
Contributor

I wouldn't expect os.path.realpath(..., strict=False) to raise OSError, no matter what coreutils does!

@nineteendo
Copy link
Contributor Author

nineteendo commented May 2, 2024

That's probably a reason which this is not part of POSIX... I expected you needed permission to follow it, not to determine the real location.

Return the canonical path of the specified filename, eliminating any symbolic links encountered in the path.

We can't eliminate this symlink, because we don't know where it points to, which we need to know for determining the parent directory. Also, coreutils doesn't even raise an error in strict mode:

wannes@Stefans-iMac ~ % ln -s . src        
wannes@Stefans-iMac ~ % grealpath -e src/..
/Users
wannes@Stefans-iMac ~ % chmod -h 000 src
wannes@Stefans-iMac ~ % grealpath -e src/..
/Users/wannes

Raising an error here will lead to the fewest bugs.

@nineteendo nineteendo reopened this May 2, 2024
@eryksun
Copy link
Contributor

eryksun commented May 2, 2024

On macOS and NetBSD, fcntl() supports F_GETPATH. In that case, you could try to open "secret-symlink" and query the resolved path, e.g. target = os.fsdecode(fcntl.fcntl(fd, fcntl.F_GETPATH, bytes(1024))). You may have to revisit the design of fcntl.fcntl() to make it use an internal buffer bigger than 1024 bytes, though I think that's currently the maximum path length supported by macOS.

@nineteendo
Copy link
Contributor Author

That works:

>>> import fcntl
>>> import os
>>> os.symlink('.', 'src')
>>> os.chmod('src', 0o000, follow_symlinks=False)
>>> os.readlink('src')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
PermissionError: [Errno 13] Permission denied: 'src'
>>> fd = os.open('src', os.O_RDONLY)
>>> os.fsdecode(fcntl.fcntl(fd, fcntl.F_GETPATH, bytes(1024))).rstrip('\x00')
'/Users/wannes'

But I think it might be cleaner to fix this in readlink...

@nineteendo
Copy link
Contributor Author

But it doesn't work for broken symlinks:

>>> import fcntl
>>> import os
>>> open('tmp', 'w', encoding='utf-8')
<_io.TextIOWrapper name='tmp' mode='w' encoding='utf-8'>
>>> os.symlink('tmp', 'dst')
>>> os.unlink('tmp')
>>> os.chmod('dst', 0o000, follow_symlinks=False)
>>> os.readlink('dst')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
PermissionError: [Errno 13] Permission denied: 'dst'
>>> fd = os.open('dst', os.O_RDONLY)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'dst'

barneygale added a commit that referenced this issue May 18, 2024
#118489)

Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 18, 2024
…path()` (pythonGH-118489)

(cherry picked from commit caf6064)

Co-authored-by: Barney Gale <barney.gale@gmail.com>
Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
barneygale added a commit to barneygale/cpython that referenced this issue May 18, 2024
…path()` (python#118489)

Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
(cherry picked from commit caf6064)
barneygale added a commit to barneygale/cpython that referenced this issue May 18, 2024
…th.realpath()` (pythonGH-118489)

Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>.
(cherry picked from commit caf6064)

Co-authored-by: Barney Gale <barney.gale@gmail.com>
barneygale added a commit that referenced this issue May 18, 2024
…lpath()` (GH-118489) (#119163)

(cherry picked from commit caf6064)

Co-authored-by: Barney Gale <barney.gale@gmail.com>
Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
barneygale added a commit to barneygale/cpython that referenced this issue May 19, 2024
Apparently only macOS requires read permission to call `readlink()` on a
symlink.
barneygale added a commit that referenced this issue May 19, 2024
Apparently only macOS requires read permission to call `readlink()` on a
symlink.
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 19, 2024
Apparently only macOS requires read permission to call `readlink()` on a
symlink.
(cherry picked from commit 4b76671)

Co-authored-by: Barney Gale <barney.gale@gmail.com>
barneygale added a commit that referenced this issue May 19, 2024
GH-118447: Fix FreeBSD test failures. (GH-119170)

Apparently only macOS requires read permission to call `readlink()` on a
symlink.
(cherry picked from commit 4b76671)

Co-authored-by: Barney Gale <barney.gale@gmail.com>
@nineteendo
Copy link
Contributor Author

With the FreeBSD test failures fixed, we can close this.

estyxx pushed a commit to estyxx/cpython that referenced this issue Jul 17, 2024
…path()` (python#118489)

Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
estyxx pushed a commit to estyxx/cpython that referenced this issue Jul 17, 2024
Apparently only macOS requires read permission to call `readlink()` on a
symlink.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants