1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* lib/fileutils.rb (remove_entry_secure): does not use chdir(2).

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9214 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
aamine 2005-09-18 20:33:01 +00:00
parent af8d063aca
commit 14d206dbb5
2 changed files with 36 additions and 25 deletions

View file

@ -1,3 +1,7 @@
Mon Sep 19 05:32:41 2005 Minero Aoki <aamine@loveruby.net>
* lib/fileutils.rb (remove_entry_secure): does not use chdir(2).
Mon Sep 19 03:17:48 2005 Tanaka Akira <akr@m17n.org> Mon Sep 19 03:17:48 2005 Tanaka Akira <akr@m17n.org>
* file.c (rb_thread_flock): wrap the flock system call by * file.c (rb_thread_flock): wrap the flock system call by

View file

@ -623,9 +623,6 @@ module FileUtils
# user (root) should invoke this method. Otherwise this method does not # user (root) should invoke this method. Otherwise this method does not
# work. # work.
# #
# WARNING: remove_entry_secure uses chdir(2), this method is not
# multi-thread safe, nor reentrant.
#
# For details of this security vulnerability, see Perl's case: # For details of this security vulnerability, see Perl's case:
# #
# http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 # http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448
@ -634,40 +631,41 @@ module FileUtils
# For fileutils.rb, this vulnerability is reported in [ruby-dev:26100]. # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100].
# #
def remove_entry_secure(path, force = false) def remove_entry_secure(path, force = false)
fullpath = File.expand_path(path) unless fu_have_symlink?
st = File.stat(File.dirname(fullpath))
unless st.world_writable?
remove_entry path, force remove_entry path, force
return return
end end
unless st.sticky? fullpath = File.expand_path(path)
raise ArgumentError, "parent directory is insecure: #{path}" st = File.lstat(fullpath)
unless st.directory?
File.unlink fullpath
return
end end
# is a directory.
parent_st = File.stat(File.dirname(fullpath))
unless parent_st.world_writable?
remove_entry path, force
return
end
unless parent_st.sticky?
raise ArgumentError, "parent directory is world writable, FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})"
end
# freeze tree root
euid = Process.euid euid = Process.euid
prevcwd = Dir.getwd File.open(fullpath + '/.') {|f|
begin unless fu_stat_identical_entry?(st, f.stat)
begin # symlink (TOC-to-TOU attack?)
Dir.chdir(fullpath)
rescue SystemCallError
# seems a file
File.unlink fullpath File.unlink fullpath
return return
end end
unless fu_stat_identical_entry?(File.lstat(fullpath), File.stat('.')) f.chown euid, -1
# seems TOC-to-TOU attack f.chmod 0700
File.unlink fullpath }
return
end
File.chown euid, nil, '.'
File.chmod 0700, '.'
ensure
Dir.chdir prevcwd
end
# ---- tree root is frozen ---- # ---- tree root is frozen ----
root = Entry_.new(path) root = Entry_.new(path)
root.preorder_traverse do |ent| root.preorder_traverse do |ent|
if ent.directory? if ent.directory?
ent.chown euid, nil ent.chown euid, -1
ent.chmod 0700 ent.chmod 0700
end end
end end
@ -682,9 +680,18 @@ module FileUtils
raise unless force raise unless force
end end
def fu_have_symlink?
File.symlink nil, nil
rescue NotImplementedError
return false
rescue
return true
end
def fu_stat_identical_entry?(a, b) def fu_stat_identical_entry?(a, b)
a.dev == b.dev and a.ino == b.ino a.dev == b.dev and a.ino == b.ino
end end
private :fu_stat_identical_entry?
# #
# This method removes a file system entry +path+. # This method removes a file system entry +path+.