Skip to content

importlib: PermissionError during startup if working directory isn't readable #115911

Closed
@moreati

Description

@moreati

Bug report

Bug description:

On macOS importlib._bootstrap_external.PathFinder._path_importer_cache() raises PermissionError during interpreter startup if '' is included in sys.path and the current working directory is not readable.

Reproduction

Given a CWD that is not readable by fred, the user fred cannot run Python

➜  private su fred -c "whoami; python3.13 -c 'pass'"
Password:
fred
Traceback (most recent call last):
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1322, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1262, in _find_spec
  File "<frozen importlib._bootstrap_external>", line 1544, in find_spec
  File "<frozen importlib._bootstrap_external>", line 1516, in _get_spec
  File "<frozen importlib._bootstrap_external>", line 1495, in _path_importer_cache
PermissionError: [Errno 13] Permission denied

➜  private uname -mv; whoami; pwd; ls -ld                                                        
Darwin Kernel Version 23.3.0: Wed Dec 20 21:30:44 PST 2023; root:xnu-10002.81.5~7/RELEASE_ARM64_T6000 arm64
alex
/Users/alex/private
drwx------  2 alex  staff  64 25 Feb 10:44 .

➜  private python3.13 -c "import sys;print(sys.version)"           
3.13.0a4+ (heads/main:6550b54813, Feb 25 2024, 10:56:11) [Clang 15.0.0 (clang-1500.1.0.2.5)]

Workaround

Adding -P, prevents '' being added to sys.path, so avoids the exception

➜  private su fred -c "whoami; python3.13 -P -c 'pass'"                                    
Password:
fred

Discussion

On macOS the libc function getcwd() can return EACCES. From the manpage

[EACCES] Read or search permission was denied for a component of the pathname. This is only checked in limited cases, depending on implementation details.

When searching for importable modules PathFinder._path_importer_cache() attempts to determine the cwd by calling os.getcwd(), it handles a FileNotFoundError exception, but not PermissionError. Because PathFinder is used during interpreter startup user code has no opportunity to catch the exception.

Proposed fix

Ignore PermissionError in PathFinder._path_importer_cache(), the same way FileNotFoundError is currently. This would result in imports succeeding, but without getting cached. E.g. applying the below change & rebuilding/reinstalling

➜  private su fred -c "whoami; python3.13 -c 'import sys;print(sys.version)'"
Password:
fred
3.13.0a4+ (heads/main:6550b54813, Feb 25 2024, 10:56:11) [Clang 15.0.0 (clang-1500.1.0.2.5)]

I'm happy to submit a PR with this, and unit tests as deemed suitable

➜  cpython git:(main) ✗ git diff
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 2a9aef0317..5d1f4f1de0 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -1493,7 +1493,7 @@ def _path_importer_cache(cls, path):
         if path == '':
             try:
                 path = _os.getcwd()
-            except FileNotFoundError:
+            except (FileNotFoundError, PermissionError):
                 # Don't cache the failure as the cwd can easily change to
                 # a valid directory later on.
                 return None

Other Python Versions

In Python 3.10, 3.11 & 3.12 the same exception can occur when user code imports a non-builtin module (e.g. base64, zlib), but it does not occur during interpreter startup. I presume this is due to a change in which modules are required during interpreter initialisation.

➜  private su fred -c "whoami; python3.10 -c 'import sys;print(sys.version);import zlib'"              
Password:
fred
3.10.13 (main, Aug 24 2023, 12:59:26) [Clang 15.0.0 (clang-1500.1.0.2.5)]
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1002, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 945, in _find_spec
  File "<frozen importlib._bootstrap_external>", line 1439, in find_spec
  File "<frozen importlib._bootstrap_external>", line 1408, in _get_spec
  File "<frozen importlib._bootstrap_external>", line 1366, in _path_importer_cache
PermissionError: [Errno 13] Permission denied

➜  private su fred -c "whoami; python3.11 -c 'import sys;print(sys.version);import zlib'"
Password:
fred
3.11.7 (main, Dec  4 2023, 18:10:11) [Clang 15.0.0 (clang-1500.1.0.2.5)]
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1138, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1078, in _find_spec
  File "<frozen importlib._bootstrap_external>", line 1504, in find_spec
  File "<frozen importlib._bootstrap_external>", line 1473, in _get_spec
  File "<frozen importlib._bootstrap_external>", line 1431, in _path_importer_cache
PermissionError: [Errno 13] Permission denied

➜  private su fred -c "whoami; python3.12 -c 'import sys;print(sys.version);import zlib'"
Password:
fred
3.12.1 (main, Dec  7 2023, 20:45:44) [Clang 15.0.0 (clang-1500.1.0.2.5)]
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1322, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1262, in _find_spec
  File "<frozen importlib._bootstrap_external>", line 1524, in find_spec
  File "<frozen importlib._bootstrap_external>", line 1496, in _get_spec
  File "<frozen importlib._bootstrap_external>", line 1475, in _path_importer_cache
PermissionError: [Errno 13] Permission denied

CPython versions tested on:

3.10, 3.11, 3.12, CPython main branch

Operating systems tested on:

macOS

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibPython modules in the Lib dirtopic-importlibtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions