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:
parent
af8d063aca
commit
14d206dbb5
2 changed files with 36 additions and 25 deletions
|
@ -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
|
||||||
|
|
|
@ -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+.
|
||||||
|
|
Loading…
Reference in a new issue