/ 最近 .rdf 追記 編集 設定 本棚

脳log[20090116] Ruby1.9.1RC1で「Insecure Operation - require (SecurityError)」が頻発する原因。



2009年01月16日 (金)

[Ruby][tDiary] Ruby1.9.1RC1で「Insecure Operation - require (SecurityError)」が頻発する原因。

20090113p0120090114p01で発生したエラーを起こす最小のスクリプトとそれを回避する方法。

>type a.rb
puts "a.rb required."

>ruby19 -v
ruby 1.9.1 (2008-12-30 patchlevel-0 revision 21203) [i386-mswin32_90]

>ruby19 -e "$SAFE=1; require 'a'"
-e:1:in `require': Insecure operation - require (SecurityError)
        from -e:1:in `<main>'

>ruby19 -e "$SAFE=1; require 'a.rb'"
a.rb required.

二つの違いは requireするライブラリの拡張子(.rb)を明示しているかどうか。拡張子なしの場合に発生する SecurityErrorは間違いだと思う。そうでないと $SAFE = 1がまるで使い物にならない。添付ライブラリだってまともに動かなくなるんだから。

ところで、Ruby 1.9 - 1.9.1 RC2 issues - Ruby Issue Tracking Systemにはチケットを作成するためのフォームがない。ruby-dev MLはアーカイブをときどき閲覧しているが購読はしていない。是非ともこの SecurityErrorは消して欲しいのだが、報告を受け付ける間口が狭い。直通ルートがない。どうすべ。


どうすべ、と言ってる間に原因究明。

 load.c:500: type = rb_find_file_ext(&tmp, loadable_ext);
 load.c:501: tmp = rb_file_expand_path(tmp, Qnil);

501行目が不要に思える。そしてこれが SecurityErrorの原因。rb_find_file_extは内部で rb_file_expand_pathや file_expand_pathを呼び、その結果を tmpにコピーしてくれている。二度目を呼ぶ必要はないのでは? rb_file_expand_pathは適宜汚染されたStringオブジェクトを返し、また $SAFE>0のとき、汚染された引数を SecurityErrorで拒絶するので、複数回の (rb_)file_expand_path呼び出しは容易に SecurityErrorを引き起こす。これは Ruby1.9.1の、Ruby1.8.7とは異なっている動作。

>irb
irb(main):001:0> File.expand_path("a")
=> "Y:/a"
irb(main):002:0> File.expand_path("a").tainted?
=> true
irb(main):003:0> File.expand_path(File.expand_path("a"))
=> "Y:/a"
irb(main):004:0> $SAFE=1
=> 1
irb(main):005:0> File.expand_path(File.expand_path("a"))
=> "Y:/a" # $SAFE>0で、taintedな文字列でも展開する。(Ruby1.8.7)
irb(main):006:0> exit

>irb19
irb(main):001:0> File.expand_path("a")
=> "Y:/a"
irb(main):002:0> File.expand_path("a").tainted?
=> true
irb(main):003:0> File.expand_path(File.expand_path("a"))
=> "Y:/a"
irb(main):004:0> $SAFE=1
=> 1
irb(main):005:0> File.expand_path(File.expand_path("a"))
 # $SAFE>0で、taintedな文字列を引数にすると SecurityError (Ruby1.9.1RC1)
SecurityError: Insecure operation - expand_path
        from (irb):5:in `expand_path'
        from (irb):5
        from C:/Program Files (x86)/ruby/bin/irb19.bat:20:in `<main>'
irb(main):006:0>

問題設定が間違っていたのか? load.cの一行をコメントアウトしたことで、たしかに一つの SecurityErrorは消えたが tDiaryは動かない。20090114p01のエラーがまだ出る。

ただ、20090114のタイトルにちらっと書いた、open-uriの SecurityErrorはでなくなってる。

>irb19 (野良パッチ済み)
irb(main):001:0> $SAFE=1
=> 1
irb(main):002:0> require 'open-uri'
=> true
irb(main):003:0> open 'http://www.example.com'
=> #<StringIO:0x2b8e924>
irb(main):004:0>

比較として ASRでエラーが出るのを確認する。ただ、ASRでも二回目以降の openはエラーにならない。謎の挙動。この SecurityErrorも本来発生すべきものではないのだろう。

>"C:\Program Files (x86)\ActiveScriptRuby-1.9.1\bin\irb.bat"
irb(main):001:0> $SAFE=1
=> 1
irb(main):002:0> require 'open-uri'
=> true
irb(main):003:0> open 'http://www.example.com'
SecurityError: Insecure operation - write
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `write'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `<<'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `<<'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:322:in `block (3 levels) in open_http'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:373:in `call_block'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:364:in `<<'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:88:in `read'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2333:in `read_body_0'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2288:in `read_body'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:321:in `block (2 levels) in open_http'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1120:in `block in transport_request'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2251:in `reading_body'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1119:in `transport_request'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1103:in `request'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:312:in `block in open_http'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:564:in `start'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:306:in `open_http'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:767:in `buffer_open'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:203:in `block in open_loop'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:201:in `catch'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:201:in `open_loop'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:146:in `open_uri'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:669:in `open'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:33:in `open'
        from (irb):3
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:21:in `<main>'
irb(main):004:0> open 'http://www.example.com'
=> #<StringIO:0x2b611a4>
irb(main):005:0>

引き続き rexml/source.rb:16の requireが SecurityErrorになる原因を探る。(tDiaryを起動しないと再現させられないのが辛い)