New submission from Alexandre Feblot <alexandre.feb...@gmail.com>:
```python #!/usr/bin/env python3 import os import tempfile def createUnremovableDir(workdir): print(workdir) os.mkdir(f'{workdir}/mydir') os.symlink('/bin/bash', f'{workdir}/mydir/mylink') # Symlink to a root owned file os.chmod(f'{workdir}/mydir', 0o555) with tempfile.TemporaryDirectory() as workdir: createUnremovableDir(workdir) ``` Fails because `tempfile.TemporaryDirectory._rmtree` tries to execute os.chmod(path, 0o700) on the symlink, which by default tries to change the root owned file symlink target instead of the symlink itself: ``` /tmp/tmp1_dy42ef Traceback (most recent call last): File "/usr/lib/python3.9/shutil.py", line 682, in _rmtree_safe_fd os.unlink(entry.name, dir_fd=topfd) PermissionError: [Errno 13] Permission denied: 'mylink' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "~/tempfile_demo_bug.py", line 13, in <module> createUnremovableDir(workdir) File "/usr/lib/python3.9/tempfile.py", line 969, in __exit__ self.cleanup() File "/usr/lib/python3.9/tempfile.py", line 973, in cleanup self._rmtree(self.name) File "/usr/lib/python3.9/tempfile.py", line 955, in _rmtree _rmtree(name, onerror=onerror) File "/usr/lib/python3.9/shutil.py", line 727, in rmtree _rmtree_safe_fd(fd, path, onerror) File "/usr/lib/python3.9/shutil.py", line 664, in _rmtree_safe_fd _rmtree_safe_fd(dirfd, fullname, onerror) File "/usr/lib/python3.9/shutil.py", line 684, in _rmtree_safe_fd onerror(os.unlink, fullname, sys.exc_info()) File "/usr/lib/python3.9/tempfile.py", line 941, in onerror resetperms(path) File "/usr/lib/python3.9/tempfile.py", line 936, in resetperms _os.chmod(path, 0o700) PermissionError: [Errno 1] Operation not permitted: '/tmp/tmp1_dy42ef/mydir/mylink' ``` and leaves: ``` (.venv python 3.9.9) $ find /tmp/tmp1_dy42ef -ls 148228 4 drwx------ 3 myuser myuser 4096 Mar 10 16:54 /tmp/tmp1_dy42ef 148229 4 drwx------ 2 myuser myuser 4096 Mar 10 16:54 /tmp/tmp1_dy42ef/mydir 148230 0 lrwxrwxrwx 1 myuser myuser 9 Mar 10 16:54 /tmp/tmp1_dy42ef/mydir/mylink -> /bin/bash ``` This fixes it: ``` python #!/usr/bin/env python3 import os import tempfile def createUnremovableDir(workdir): print(workdir) os.mkdir(f'{workdir}/mydir') os.symlink('/bin/bash', f'{workdir}/mydir/mylink') # Symlink to a root owned file os.chmod(f'{workdir}/mydir', 0o555) def _rmtree(cls, name, ignore_errors=False): def onerror(func, path, exc_info): if issubclass(exc_info[0], PermissionError): def resetperms(path): try: if os.chflags in os.supports_follow_symlinks: # This is the patch os.chflags(path, 0, follow_symlinks=False) # This is the patch elif not os.path.islink(path): # This is the patch os.chflags(path, 0) except AttributeError: pass if os.chmod in os.supports_follow_symlinks: # This is the patch os.chmod(path, 0o700, follow_symlinks=False) # This is the patch elif not os.path.islink(path): # This is the patch os.chmod(path, 0o700) try: if path != name: resetperms(os.path.dirname(path)) resetperms(path) try: os.unlink(path) # PermissionError is raised on FreeBSD for directories except (IsADirectoryError, PermissionError): cls._rmtree(path, ignore_errors=ignore_errors) except FileNotFoundError: pass elif issubclass(exc_info[0], FileNotFoundError): pass else: if not ignore_errors: raise shutil.rmtree(name, onerror=onerror) # Monkey patch the class method tempfile.TemporaryDirectory._rmtree from types import MethodType import shutil tempfile.TemporaryDirectory._rmtree = MethodType(_rmtree, tempfile.TemporaryDirectory) with tempfile.TemporaryDirectory() as workdir: createUnremovableDir(workdir) ---------- components: Library (Lib) messages: 414871 nosy: afeblot priority: normal severity: normal status: open title: tempfile.TemporaryDirectory fails removing dir in some edge cases related to symlinks versions: Python 3.9 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue46977> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com