[Python-checkins] cpython: Issue #4489: Rename the feature marker for the symlink resistant rmtree and

nick.coghlan python-checkins at python.org
Sun Jun 24 08:43:20 CEST 2012


http://hg.python.org/cpython/rev/c2be81151994
changeset:   77668:c2be81151994
user:        Nick Coghlan <ncoghlan at gmail.com>
date:        Sun Jun 24 16:43:06 2012 +1000
summary:
  Issue #4489: Rename the feature marker for the symlink resistant rmtree and store it as a function attribute

files:
  Doc/library/shutil.rst  |  29 +++++++++++++++--------------
  Doc/whatsnew/3.3.rst    |   5 +++++
  Lib/shutil.py           |   8 ++++++--
  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
--- a/Doc/library/shutil.rst
+++ b/Doc/library/shutil.rst
@@ -190,14 +190,15 @@
    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 @@
    :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
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -1296,6 +1296,11 @@
   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
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -405,8 +405,9 @@
     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 @@
     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
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -487,7 +487,7 @@
     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 @@
                 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.

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list