diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2012-06-24 06:43:06 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2012-06-24 06:43:06 (GMT) |
commit | 5b0eca116ad1b9509ebe4620f1685d86ce4433bf (patch) | |
tree | 06028b901fd8bd82fb14cf108c399b8626dce196 | |
parent | 8e5c0a774fd8c51fdf5654a6d6688a09e62d6c5e (diff) | |
download | cpython-5b0eca116ad1b9509ebe4620f1685d86ce4433bf.zip cpython-5b0eca116ad1b9509ebe4620f1685d86ce4433bf.tar.gz cpython-5b0eca116ad1b9509ebe4620f1685d86ce4433bf.tar.bz2 |
Issue #4489: Rename the feature marker for the symlink resistant rmtree and store it as a function attribute
-rw-r--r-- | Doc/library/shutil.rst | 29 | ||||
-rw-r--r-- | Doc/whatsnew/3.3.rst | 5 | ||||
-rw-r--r-- | Lib/shutil.py | 8 | ||||
-rw-r--r-- | Lib/test/test_shutil.py | 4 |
4 files changed, 28 insertions, 18 deletions
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 5521841..7526e5e 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -190,14 +190,15 @@ Directory and files operations handled by calling a handler specified by *onerror* or, if that is omitted, they raise an exception. - .. warning:: + .. note:: - The default :func:`rmtree` function is susceptible to a symlink attack: - given proper timing and circumstances, attackers can use it to delete - files they wouldn't be able to access otherwise. Thus -- on platforms - that support the necessary fd-based functions -- a safe version of - :func:`rmtree` is used, which isn't vulnerable. In this case - :data:`rmtree_is_safe` is set to True. + On platforms that support the necessary fd-based functions a symlink + attack resistant version of :func:`rmtree` is used by default. On other + platforms, the :func:`rmtree` implementation is susceptible to a + symlink attack: given proper timing and circumstances, attackers can + manipulate symlinks on the filesystem to delete files they wouldn't + be able to access otherwise. Applications can use the :data:`rmtree.avoids_symlink_attacks` function attribute to + determine which case applies. If *onerror* is provided, it must be a callable that accepts three parameters: *function*, *path*, and *excinfo*. @@ -209,16 +210,16 @@ Directory and files operations :func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught. .. versionchanged:: 3.3 - Added a safe version that is used automatically if platform supports - fd-based functions. + Added a symlink attack resistant version that is used automatically + if platform supports fd-based functions. -.. data:: rmtree_is_safe + .. data:: rmtree.avoids_symlink_attacks - Indicates whether the current platform and implementation has a symlink - attack-proof version of :func:`rmtree`. Currently this is only true for - platforms supporting fd-based directory access functions. + Indicates whether the current platform and implementation provides a + symlink attack resistant version of :func:`rmtree`. Currently this is + only true for platforms supporting fd-based directory access functions. - .. versionadded:: 3.3 + .. versionadded:: 3.3 .. function:: move(src, dst) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 25a0ece..e97ac86 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1296,6 +1296,11 @@ shutil acts on the symlink itself (or creates one, if relevant). (Contributed by Hynek Schlawack in :issue:`12715`.) +* :func:`~shutil.rmtree` is now resistant to symlink attacks on platforms + which support the new ``dir_fd`` parameter in :func:`os.open` and + :func:`os.unlinkat`. (Contributed by Martin von Löwis and Hynek Schlawack + in :issue:`4489`.) + signal diff --git a/Lib/shutil.py b/Lib/shutil.py index f743d05..2c00f4a 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -405,8 +405,9 @@ def _rmtree_safe_fd(topfd, path, onerror): except os.error: onerror(os.rmdir, path, sys.exc_info()) -rmtree_is_safe = _use_fd_functions = (os.unlink in os.supports_dir_fd and - os.open in os.supports_dir_fd) +_use_fd_functions = (os.unlink in os.supports_dir_fd and + os.open in os.supports_dir_fd) + def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. @@ -449,6 +450,9 @@ def rmtree(path, ignore_errors=False, onerror=None): else: return _rmtree_unsafe(path, onerror) +# Allow introspection of whether or not the hardening against symlink +# attacks is supported on the current platform +rmtree.avoids_symlink_attacks = _use_fd_functions def _basename(path): # A basename() variant which first strips the trailing slash, if present. diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index b2ac0cf..067889e 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -487,7 +487,7 @@ class TestShutil(unittest.TestCase): def test_rmtree_uses_safe_fd_version_if_available(self): if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd: self.assertTrue(shutil._use_fd_functions) - self.assertTrue(shutil.rmtree_is_safe) + self.assertTrue(shutil.rmtree.avoids_symlink_attacks) tmp_dir = self.mkdtemp() d = os.path.join(tmp_dir, 'a') os.mkdir(d) @@ -502,7 +502,7 @@ class TestShutil(unittest.TestCase): shutil._rmtree_safe_fd = real_rmtree else: self.assertFalse(shutil._use_fd_functions) - self.assertFalse(shutil.rmtree_is_safe) + self.assertFalse(shutil.rmtree.avoids_symlink_attacks) def test_rmtree_dont_delete_file(self): # When called on a file instead of a directory, don't delete it. |