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

GH-118447: Fix handling of unreadable symlinks in os.path.realpath() #118489

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

barneygale
Copy link
Contributor

@barneygale barneygale commented May 1, 2024

@bedevere-app bedevere-app bot added the tests Tests in the Lib/test dir label May 1, 2024
@barneygale barneygale changed the title GH-118447: Handle unreadable symlinks in os.path.realpath() GH-118447: Fix handling of unreadable symlinks in os.path.realpath() May 1, 2024
@barneygale barneygale removed the tests Tests in the Lib/test dir label May 1, 2024
@barneygale barneygale marked this pull request as ready for review May 1, 2024 22:06
nineteendo

This comment was marked as resolved.

@barneygale
Copy link
Contributor Author

If not resolving unreadable symlinks is acceptable, you still need to raise an error for link/...

realpath() shouldn't raise OSError in non-strict mode.

# use cached value
continue
# The symlink is not resolved, so we must have a symlink loop.
raise OSError(errno.ELOOP, "Symlink loop", newpath)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not keep os.stat(newpath) here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with the way we raise NotADirectoryError in #118290, and to save the small cost of a stat()

@@ -660,6 +660,20 @@ def test_realpath_resolve_first(self):
safe_rmdir(ABSTFN + "/k")
safe_rmdir(ABSTFN)

@os_helper.skip_unless_symlink
@skip_if_ABSTFN_contains_backslash
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it needed? How does the test work on Windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't work on Windows because ABSTFN is an absolute path with backslash separators. These decorators are also used for other tests in this suite.

try:
os.symlink(ABSTFN+"1", ABSTFN)
os.chmod(ABSTFN, 0o000, follow_symlinks=False)
self.assertEqual(realpath(ABSTFN), ABSTFN)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please test also cases where non-readable symlink is followed by other path components (including ..), e.g. badlink/foo, badlink/../foo, badlink/foo/.., etc.

If the following .. removes badlink, try to test something that involves a loop containing badlink, if this is possible. Your code does not set seen[newpath] = None before calling readlink(), I wonder what effect does it have.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.assertEqual(realpath(ABSTFN), ABSTFN)
self.assertEqual(realpath(ABSTFN), ABSTFN)
self.assertEqual(realpath(ABSTFN + '/foo'), ABSTFN + '/foo')
self.assertEqual(realpath(ABSTFN + '/../foo'), dirname(ABSTFN) + '/foo')
self.assertEqual(realpath(ABSTFN + '/foo/..'), ABSTFN)

Copy link
Contributor

@nineteendo nineteendo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, you're right, it shouldn't raise an error. That's what strict is for.

@serhiy-storchaka
Copy link
Member

I think that it is reasonable to expect that realpath('dir/badlink/rest') returns the same result when badlink does not exist, is a file, is in non-readable directory or is non-readable itself, for any rest. It's error prone, but that's how it was defined.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants