続 汚染されたクラスの利用
keita_yamaguchi さんより、最新のRubyでは汚染状態によるメソッド呼び出しの制限が修正されているとの情報を頂いたので(ありがとうございます!)、最新のRubyをインストールして試してみました。
$ ruby -v ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-cygwin]
1.8.7-p72でのメソッド呼び出しの制限
- セーフレベル0〜2では、汚染されたメソッド(=汚染されたクラスのメソッド)を実行できない。
- ruby 1.8.6-p0(昨日試したもの)はセーフレベル0の場合のみ実行できず、1or2の場合は実行できます。
- セーフレベル4では、汚染されていないインスタンスのsetメソッドを実行できない。
- もちろん、メソッド内で各セーフレベルで禁止されている行為(ファイルの書き込みなど)を行っている場合はこの限りではないですよ。
セーフレベル0-2 | セーフレベル3 | セーフレベル4 | |
---|---|---|---|
クラス:汚染/インスタンス:汚染 | × | ○ | ○ |
クラス:通常/インスタンス:汚染 | ○ | ○ | ○ |
クラス:汚染/インスタンス:通常 | × | ○ | ×(setのみ/getは可) |
クラス:通常/インスタンス:通常 | ○ | ○ | ×(setのみ/getは可) |
検証に使用したコード
ちょっと長いですが、載せておきます。
class Variation def initialize( name ) @name = name end def exec( context ) yield end attr :name end class Branch def initialize(prev=nil) @prev = prev @variations = [] end def <<( variation ) @variations << variation end def next_branch @next = Branch.new(self) @next end def exec( context=Context.new, &block ) root = self root = root.prev while root.prev != nil root._exec( context, block ) end def _exec( context, block ) @variations.each {|v| begin context.steps.push v.name v.exec( context ) { if @next @next._exec( context, block ) else block.call(context) if block end } ensure context.steps.pop end } end attr :next attr :prev end class Context def initialize( option={} ) @steps = [] @option = option end def path @steps.join("/") end def []=(k,v) @option[k] = v end def [](k) @option[k] end attr :steps attr :option, true end # クラスの汚染状態 class ClassTaint < Variation def initialize( name, cl ) @name = name @cl = cl end def exec( context ) obj = @cl.new begin context[:class] = @cl context[:obj] = obj yield ensure context[:class] = nil context[:obj] = nil end end end # インスタンスの汚染状態 class InstanceTaint < Variation def initialize( name, taint ) @name = name @taint = taint end def exec( context ) begin context[:obj].taint if @taint yield ensure context[:obj].untaint if @taint end end end # 呼び出し元のセーフレベル class SafeLevel < Variation def initialize( name, level ) @name = name @level = level end def exec( context ) # getメソッドを実行し、結果をコンテキストに積む context[:result_get] = Thread.fork { obj = context[:obj] $SAFE = @level begin obj.test true rescue SecurityError false end }.value # setメソッドを実行し、結果をコンテキストに積む context[:result_set] = Thread.fork { obj = context[:obj] $SAFE = @level begin obj.test="a" true rescue SecurityError false end }.value yield context[:result_get] = false context[:result_set] = false end end # 通常のクラス normal_class = class NormalClass def test @test end def test=(test) @test = test end self end # 汚染されたクラスその1 tainted_class = Thread.fork { $SAFE = 3 class TaintedClass def test @test end def test=(test) @test = test end self end }.value b = Branch.new b << ClassTaint.new( "class:taint", tainted_class ) b << ClassTaint.new( "class:normal", normal_class ) b = b.next_branch b << InstanceTaint.new( "instance:taint", true ) b << InstanceTaint.new( "instance:normal", false ) b = b.next_branch b << SafeLevel.new( "safe_level:0", 0 ) b << SafeLevel.new( "safe_level:1", 1 ) b << SafeLevel.new( "safe_level:2", 2 ) b << SafeLevel.new( "safe_level:3", 3 ) b << SafeLevel.new( "safe_level:4", 4 ) b.exec {|c| puts <<-STR --#{c.path} class tainted? : #{c[:class].tainted?} object tainted? : #{c[:obj].tainted?} get_method tainted? : #{c[:obj].method(:test).tainted?} set_method tainted? : #{c[:obj].method(:test=).tainted?} get_method invoke : #{c[:result_get] ? "ok" : "no"} set_method invoke : #{c[:result_set] ? "ok" : "no"} STR }
実行結果です。
--class:taint/instance:taint/safe_level:0 class tainted? : true object tainted? : true get_method tainted? : true set_method tainted? : true get_method invoke : no set_method invoke : no --class:taint/instance:taint/safe_level:1 class tainted? : true object tainted? : true get_method tainted? : true set_method tainted? : true get_method invoke : no set_method invoke : no --class:taint/instance:taint/safe_level:2 class tainted? : true object tainted? : true get_method tainted? : true set_method tainted? : true get_method invoke : no set_method invoke : no --class:taint/instance:taint/safe_level:3 class tainted? : true object tainted? : true get_method tainted? : true set_method tainted? : true get_method invoke : ok set_method invoke : ok --class:taint/instance:taint/safe_level:4 class tainted? : true object tainted? : true get_method tainted? : true set_method tainted? : true get_method invoke : ok set_method invoke : ok --class:taint/instance:normal/safe_level:0 class tainted? : true object tainted? : false get_method tainted? : true set_method tainted? : true get_method invoke : no set_method invoke : no --class:taint/instance:normal/safe_level:1 class tainted? : true object tainted? : false get_method tainted? : true set_method tainted? : true get_method invoke : no set_method invoke : no --class:taint/instance:normal/safe_level:2 class tainted? : true object tainted? : false get_method tainted? : true set_method tainted? : true get_method invoke : no set_method invoke : no --class:taint/instance:normal/safe_level:3 class tainted? : true object tainted? : false get_method tainted? : true set_method tainted? : true get_method invoke : ok set_method invoke : ok --class:taint/instance:normal/safe_level:4 class tainted? : true object tainted? : false get_method tainted? : true set_method tainted? : true get_method invoke : ok set_method invoke : no --class:normal/instance:taint/safe_level:0 class tainted? : false object tainted? : true get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:taint/safe_level:1 class tainted? : false object tainted? : true get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:taint/safe_level:2 class tainted? : false object tainted? : true get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:taint/safe_level:3 class tainted? : false object tainted? : true get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:taint/safe_level:4 class tainted? : false object tainted? : true get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:normal/safe_level:0 class tainted? : false object tainted? : false get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:normal/safe_level:1 class tainted? : false object tainted? : false get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:normal/safe_level:2 class tainted? : false object tainted? : false get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:normal/safe_level:3 class tainted? : false object tainted? : false get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : ok --class:normal/instance:normal/safe_level:4 class tainted? : false object tainted? : false get_method tainted? : false set_method tainted? : false get_method invoke : ok set_method invoke : no