history

青木日記 RSS

<前の日 | この月 | 次の日>

2005-05-25

rm -rf が効かない!?

fileutils.rb のテストをしてたら変なことが起こった。

/tmp % ruby -e 'Dir.mkdir"a"; 20000.times{|i| open("a/#{i}","w"){}; open("a/passwd","w"){} }'
/tmp % rm -rf a || ls a | wc -l
rm: cannot remove directory `a': Directory not empty
   9926
/tmp % rm -rf a || ls a | wc -l
rm: cannot remove directory `a': Directory not empty
   4817
/tmp % rm -rf a || ls a | wc -l
rm: cannot remove directory `a': Directory not empty
   2334
/tmp % rm -rf a || ls a | wc -l
rm: cannot remove directory `a': Directory not empty
   1022
/tmp % rm -rf a || ls a | wc -l
rm: cannot remove directory `a': Directory not empty
    436
/tmp % rm -rf a || ls a | wc -l
rm: cannot remove directory `a': Directory not empty
    144
/tmp % rm -rf a || ls a | wc -l

エントリが半分ずつしか減らない。いったいどうなってるんだ。

ちなみに /tmp 以外だと何も問題はない。

~/tmp % ruby -e 'Dir.mkdir"a"; 20000.times{|i| open("a/#{i}","w"){}; open("a/passwd","w"){} }'
~/tmp % rm -rf
~/tmp % ls a
ls: a: No such file or directory

これはもしかして tmpfs のバグか?

/tmp % uname -srm
Linux 2.4.22 i686
/tmp % mount | grep tmp
none on /tmp type tmpfs (rw,mode=1777,size=64m)

報告されてた。これだな。

新しいバージョンでは修正されてんのかな。

/d/src/linux-2.4.30 % grep tmpfs ChangeLog-2.4.*
ChangeLog-2.4.23:  o tmpfs 1/5 LTP ENAMETOOLONG
ChangeLog-2.4.23:  o tmpfs 2/5 LTP S_ISGID dir
ChangeLog-2.4.23:  o tmpfs 3/5 swapoff/truncate race
ChangeLog-2.4.23:  o tmpfs 4/5 getpage/truncate race
ChangeLog-2.4.23:  o tmpfs 5/5 writepage/truncate race
ChangeLog-2.4.25:  o tmpfs readdir does not update dir atime
ChangeLog-2.4.25:  o Fix tmpfs dcache oops
ChangeLog-2.4.27:  o tmpfs surplus page miscounted
ChangeLog-2.4.28:  o tmpfs: stop negative dentries
ChangeLog-2.4.28:  o tmpfs: fix shmem_file_write return value

いっぱいあった。2.4.28 以降なら大丈夫そう?

(19:27)

FileUtils.rm_rf (8)

次のような攻撃ができる可能性はあるんだろうか。 両プロセスのカレントディレクトリは /tmp で、 /tmp のパーミッションは 1777 とする。

rm -rf プロセス(euid=0)  クラックプロセス(euid=1000)
---------------------------------------------------------------------
                         (プログラム cmd を作り chmod(01777, "cmd"))
                         chmod(01777, "cmd")
                         mkdir("a")
readdir("/tmp")
unlink("a") = EISDIR
                         rmdir("a")
                         rename("cmd", "a")
lchown(0, "a")
                         execl("./a")        # setuid root で動作?
lchmod(0700, "a")

Linux 2.4 では lchown(2) で suid bit がクリアされたけど、 SUSv3 によると実装依存らしい。

If the specified file is a regular file, one or more of the S_IXUSR,
S_IXGRP, or S_IXOTH bits of the file mode are set, and the process has
appropriate privileges, it is implementation-defined whether the
set-user-ID and set-group-ID bits are altered.

……だりい……。 家にあるシステムを片端から実行してみて問題なければ OKってことにしちゃおうかなあ……。

アプリケーションを特定できればなんとかなるはずなんだよなあ。 万能のメソッドを一個だけ作ろうとするから無理なわけで……。

結論は fork, setuid, chdir ってことで。冗談です。

うーん、open したディレクトリに対して chown とか chmod できればいいのかなあ。 それなら普通に stat が使えるし。

え、いや違うか、 open する対象がすりかえられたら回避できない?! そうか、だから lchown が必要なんだっけ。 なんだ、それじゃ lchown が suid bit をクリアしないシステムでは どうやってもセキュアにはならないんだな。 それならクリアされるほうに賭けたほうが得だ。

非破壊検査 / シンボリックリンク

テンポラリファイルを使わずに調べよう、 シンボリックリンク編

/tmp % cat /d/tmp/have-symlink-p.rb
def have_symlink?
  File.symlink nil, nil
rescue NotImplementedError
  return false
rescue
  return true
end
 
p have_symlink?
 
/tmp % test-all-ruby /d/tmp/have-symlink-p.rb
ruby 1.4.6 (2000-08-16) [i686-linux]
/d/tmp/have-symlink-p.rb:3: parse error
rescue NotImplementedError
^
/d/tmp/have-symlink-p.rb:3: warning: useless use of a constant in void context
/d/tmp/have-symlink-p.rb:5: parse error
ruby 1.6.0 (2000-09-19) [i686-linux]
true
ruby 1.6.1 (2000-09-27) [i686-linux]
true
ruby 1.6.2 (2000-12-25) [i686-linux]
true
ruby 1.6.3 (2001-03-19) [i686-linux]
true
ruby 1.6.4 (2001-06-04) [i686-linux]
true
ruby 1.6.5 (2001-09-19) [i686-linux]
true
ruby 1.6.6 (2001-12-26) [i686-linux]
true
ruby 1.6.7 (2002-03-01) [i686-linux]
true
ruby 1.6.8 (2002-12-24) [i686-linux]
true
ruby 1.8.0 (2003-08-04) [i686-linux]
true
ruby 1.8.1 (2003-12-25) [i686-linux]
true
ruby 1.9.0 (2005-05-16) [i686-linux]
true

Windows での状況

~/src/ruby % ruby-vc6 -v have-symlink-p.rb
ruby 1.9.0 (2005-03-28) [i386-mswin32]
false
~/src/ruby % ruby-cygwin -v have-symlink-p.rb
ruby 1.9.0 (2005-03-28) [i386-cygwin]
true

ハードリンクも同じようにすれば調べられる。

しかし、なんか妙な知識ばっかり蓄積されてくなあ。

(02:20)

名前
メールアドレス

<前の日 | この月 | 次の日>
2002|04|05|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|04|05|06|09|10|
2009|07|
2010|09|

Copyright (c) 2002-2007 青木峰郎 / Minero Aoki. All rights reserved. LIRS