[前][次][番号順一覧][スレッド一覧]

ruby-changes:72072

From: Burdette <ko1@a...>
Date: Tue, 7 Jun 2022 00:37:49 +0900 (JST)
Subject: [ruby-changes:72072] b737998d25 (master): [ruby/fileutils] [DOC] Enhanced RDoc for FileUtils (https://github.com/ruby/fileutils/pull/78)

https://git.ruby-lang.org/ruby.git/commit/?id=b737998d25

From b737998d25f1379117fbf11a578462e6ba12037e Mon Sep 17 00:00:00 2001
From: Burdette Lamar <BurdetteLamar@Y...>
Date: Mon, 6 Jun 2022 10:37:18 -0500
Subject: [ruby/fileutils] [DOC] Enhanced RDoc for FileUtils
 (https://github.com/ruby/fileutils/pull/78)

Treats:
    ::rm
    ::rm_f
    ::rm_r
    ::rm_rf
    ::remove_entry_secure

https://github.com/ruby/fileutils/commit/ce2a438d75
---
 lib/fileutils.rb | 204 ++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 142 insertions(+), 62 deletions(-)

diff --git a/lib/fileutils.rb b/lib/fileutils.rb
index f072b770fc..cbf7f526c6 100644
--- a/lib/fileutils.rb
+++ b/lib/fileutils.rb
@@ -101,6 +101,57 @@ end https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L101
 # files/directories.  This equates to passing the <tt>:noop</tt> and
 # <tt>:verbose</tt> flags to methods in FileUtils.
 #
+# == Avoiding the TOCTTOU Vulnerability
+#
+# For certain methods that recursively remove entries,
+# there is a potential vulnerability called the
+# {Time-of-check to time-of-use}[https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use],
+# or TOCTTOU, vulnerability that can exist when:
+#
+# - An ancestor directory of the entry at the target path is world writable;
+#   such directories include <tt>/tmp</tt>.
+# - The directory tree at the target path includes:
+#
+#   - A world-writable descendant directory.
+#   - A symbolic link.
+#
+# To avoid that vulnerability, you can use this method to remove entries:
+#
+# - FileUtils.remove_entry_secure: removes recursively
+#   if the target path points to a directory.
+#
+# Also available are these methods,
+# each of which calls \FileUtils.remove_entry_secure:
+#
+# - FileUtils.rm_r with keyword argument <tt>secure: true</tt>.
+# - FileUtils.rm_rf with keyword argument <tt>secure: true</tt>.
+#
+# Finally, this method for moving entries calls \FileUtils.remove_entry_secure
+# if the source and destination are on different devices
+# (which means that the "move" is really a copy and remove):
+#
+# - FileUtils.mv with keyword argument <tt>secure: true</tt>.
+#
+# \Method \FileUtils.remove_entry_secure removes securely
+# by applying a special pre-process:
+#
+# - If the target path points to a directory, this method uses
+#   {chown(2)}[https://man7.org/linux/man-pages/man2/chown.2.html]
+#   and {chmod(2)}[https://man7.org/linux/man-pages/man2/chmod.2.html]
+#   in removing directories.
+# - The owner of the target directory should be either the current process
+#   or the super user (root).
+#
+# WARNING: You must ensure that *ALL* parent directories cannot be
+# moved by other untrusted users.  For example, parent directories
+# should not be owned by untrusted users, and should not be world
+# writable except when the sticky bit is set.
+#
+# For details of this security vulnerability, see Perl cases:
+#
+# - {CVE-2005-0448}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448].
+# - {CVE-2004-0452}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452].
+#
 module FileUtils
   VERSION = "1.6.0"
 
@@ -197,7 +248,7 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L248
   #
   # Creates directories at the paths in the given +list+
   # (an array of strings or a single string);
-  # returns +list+.
+  # returns +list+ if it is an array, <tt>[list]</tt> otherwise.
   #
   # With no keyword arguments, creates a directory at each +path+ in +list+
   # by calling: <tt>Dir.mkdir(path, mode)</tt>;
@@ -239,7 +290,7 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L290
   # Creates directories at the paths in the given +list+
   # (an array of strings or a single string),
   # also creating ancestor directories as needed;
-  # returns +list+.
+  # returns +list+ if it is an array, <tt>[list]</tt> otherwise.
   #
   # With no keyword arguments, creates a directory at each +path+ in +list+,
   # along with any needed ancestor directories,
@@ -311,7 +362,7 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L362
   #
   # Removes directories at the paths in the given +list+
   # (an array of strings or a single string);
-  # returns +list+.
+  # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
   #
   # With no keyword arguments, removes the directory at each +path+ in +list+,
   # by calling: <tt>Dir.rmdir(path)</tt>;
@@ -865,6 +916,10 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L916
   # If +src+ and +dest+ are on different devices,
   # first copies, then removes +src+.
   #
+  # May cause a local vulnerability if not called with keyword argument
+  # <tt>secure: true</tt>;
+  # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
+  #
   # If +src+ is the path to a single file or directory and +dest+ does not exist,
   # moves +src+ to +dest+:
   #
@@ -898,13 +953,14 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L953
   #   |   `-- src.txt
   #   `-- src1.txt
   #
-  # - <tt>force: true</tt> - attempts to force the move;
-  #   if the move includes removing +src+
+  # Keyword arguments:
+  #
+  # - <tt>force: true</tt> - if the move includes removing +src+
   #   (that is, if +src+ and +dest+ are on different devices),
   #   ignores raised exceptions of StandardError and its descendants.
   # - <tt>noop: true</tt> - does not move files.
-  # - <tt>secure: true</tt> - removes +src+ securely
-  #   by calling FileUtils.remove_entry_secure.
+  # - <tt>secure: true</tt> - removes +src+ securely;
+  #   see details at FileUtils.remove_entry_secure.
   # - <tt>verbose: true</tt> - prints an equivalent command:
   #
   #     FileUtils.mv('src0', 'dest0', noop: true, verbose: true)
@@ -949,13 +1005,29 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L1005
   alias move mv
   module_function :move
 
+  # Removes entries at the paths in the given +list+
+  # (an array of strings or a single string);
+  # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
+  #
+  # With no keyword arguments, removes files at the paths given in +list+:
+  #
+  #   FileUtils.touch(['src0.txt', 'src0.dat'])
+  #   FileUtils.rm(['src0.dat', 'src0.txt']) # => ["src0.dat", "src0.txt"]
+  #
+  # Keyword arguments:
+  #
+  # - <tt>force: true</tt> - ignores raised exceptions of StandardError
+  #   and its descendants.
+  # - <tt>noop: true</tt> - does not remove files; returns +nil+.
+  # - <tt>verbose: true</tt> - prints an equivalent command:
+  #
+  #     FileUtils.rm(['src0.dat', 'src0.txt'], noop: true, verbose: true)
+  #
+  #   Output:
   #
-  # Remove file(s) specified in +list+.  This method cannot remove directories.
-  # All StandardErrors are ignored when the :force option is set.
+  #     rm src0.dat src0.txt
   #
-  #   FileUtils.rm %w( junk.txt dust.txt )
-  #   FileUtils.rm Dir.glob('*.so')
-  #   FileUtils.rm 'NotExistFile', force: true   # never raises exception
+  # FileUtils.remove is an alias for FileUtils.rm.
   #
   def rm(list, force: nil, noop: nil, verbose: nil)
     list = fu_list(list)
@@ -971,10 +1043,13 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L1043
   alias remove rm
   module_function :remove
 
+  # Equivalent to:
   #
-  # Equivalent to
+  #   FileUtils.rm(list, force: true, **kwargs)
   #
-  #   FileUtils.rm(list, force: true)
+  # See FileUtils.rm for keyword arguments.
+  #
+  # FileUtils.safe_unlink is an alias for FileUtils.rm_f.
   #
   def rm_f(list, noop: nil, verbose: nil)
     rm list, force: true, noop: noop, verbose: verbose
@@ -984,24 +1059,50 @@ module FileUtils https://github.com/ruby/ruby/blob/trunk/lib/fileutils.rb#L1059
   alias safe_unlink rm_f
   module_function :safe_unlink
 
+  # Removes entries at the paths in the given +list+
+  # (an array of strings or a single string);
+  # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
   #
-  # remove files +list+[0] +list+[1]... If +list+[n] is a directory,
-  # removes its all contents recursively. This method ignores
-  # StandardError when :force option is set.
+  # May cause a local vulnerability if not called with keyword argument
+  # <tt>secure: true</tt>;
+  # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
   #
-  #   FileUtils.rm_r Dir.glob('/tmp/*')
-  #   FileUtils.rm_r 'some_dir', force: true
+  # For each file path, removes the file at that path:
   #
-  # WARNING: This method causes local vulnerability
-  # if one of parent directories or removing directory tree are world
-  # writable (including /tmp, whose permission is 1777), and the current
-  # process has strong privilege such as Unix super user (root), and the
-  # system has symbolic link.  For secure removing, read the documentation
-  # of remove_entry_secure carefully, and set :secure option to true.
-  # Default is <tt>secure: false</tt>.
+  #   FileUtils.touch(['src0.txt', 'src0.dat'])
+  #   FileUtils.rm_r(['src0.dat', 'src0.txt'])
+  #   File.exist?('src0.txt') # => false
+  #   File.exist?('src0.dat') # => false
   #
-  # NOTE: This method calls remove_entry_secure if :secure option is set.
-  # See also remove_entry_secure.
+  # For each directory path, recursively removes files and directories:
+  #
+  #   system('tree --charset=ascii src1')
+  #   src1
+  #   |-- dir0
+  #   |   |-- src0.txt
+  #   |   `-- src1.txt
+  #   `-- dir1
+  #       |-- src2.txt
+  #       `-- src3.txt
+  #   FileUtils.rm_r('src1')
+  #   File.exist?('src1') # => false
+  #
+  # Keyword arguments:
+  #
+  # - <tt>force: true</tt> - ignores raised exceptions of StandardError
+  #   and its descendants.
+  # - <tt>noop: true</tt> - does not remove entries; returns +nil+.
+  # - <tt>secure: true</tt> - removes +src+ securely;
+  #   see details at FileUtils.remove_entry_secure.
+  # - <tt>verbose: true</tt> - prints an equivalent command:
+  # (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]