読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

続 汚染されたクラスの利用

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