[issue46977] tempfile.TemporaryDirectory fails removing dir in some edge cases related to symlinks

2022-03-10 Thread Alexandre Feblot


Change by Alexandre Feblot :


--
type:  -> crash

___
Python tracker 
<https://bugs.python.org/issue46977>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue46977] tempfile.TemporaryDirectory fails removing dir in some edge cases related to symlinks

2022-03-10 Thread Alexandre Feblot


New submission from Alexandre Feblot :

```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 
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 myuser9 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 
<https://bugs.python.org/issue46977>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com