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

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

セーフレベル4でのクラス定義

Ruby

セーフレベル4ではトップレベルへのクラスの追加はできませんが、汚れたモジュールを用意してそこに追加することは可能です。

# ブロックを実行し、SecurityErrorとなるのを確認する。
def expects_security_error 
  begin
    yield if block_given?
    raise "期待と違う"
  rescue SecurityError
  end
end

# 指定のSAFEレベルでブロックを実行する。
def safe( level ) 
  Thread.fork {
    $SAFE = level
    yield if block_given?
  }.value
end


# 汚染されたクラス生成コード
class_str = <<CLASS_DEF 
  class Foo
    def initialize
      'init'
    end
    def foo
      'foo'
    end
    def hoge
      "a".taint
    end
  end
  class Var
    def var
      'var'
    end
  end
CLASS_DEF
class_str.taint # 汚す。


# セーフレベル4ではクラスを追加/変更できないが・・・
safe(4) {
  # クラスの追加
  expects_security_error {
    class Var; end
  }
  # 汚されていない既存クラスの変更
  expects_security_error {
    class String
      def foo; "foo" end 
    end
  }
  # evalでのクラスの追加
  expects_security_error {
    eval class_str
  }
  eval "1+1" # eval自体はできるよ。
}

# 汚れたモジュールに対しては追加できる。
TaintModule = Module.new.taint # 汚らわしいモジュール
safe(4) {
  TaintModule.module_eval class_str
}
# 追加されたクラスは汚染されている。
puts TaintModule::Foo.tainted?
puts TaintModule::Var.tainted?
puts TaintModule::Foo.instance_method(:initialize).tainted?
puts TaintModule::Var.instance_method(:initialize).tainted? # これだけfalse
puts TaintModule::Foo.instance_method(:foo).tainted?
puts TaintModule::Var.instance_method(:var).tainted?

# 汚染されていないモジュールだと追加できない。
NoTaintModule = Module.new
safe(4) {
  expects_security_error {
    NoTaintModule.module_eval class_str
  }
}

実行結果です。

true
true
true
false
true
true

定義したクラスを使う。

  • セーフレベル4で定義されたクラス(とクラスのメソッド)は汚染された状態になります。
  • 汚染されたクラスをセーフレベル0で使う(メソッドコンストラクタを呼び出す)とSecurityErrorになります。
  • 汚染されたメソッドは強制的にセーフレベル4で実行されます。
# コンストラクタが汚染されていると、
# セーフレベル0ではそのインスタンスを生成できない。
expects_security_error {
  f = TaintModule::Foo.new
}
v = TaintModule::Var.new # コンストラクタの定義がなければ作成はOK
expects_security_error {
  v.var # でも汚染されたメソッドの呼び出しはエラー
}

# セーフレベルが1以上なら呼び出せる。
puts safe(1) {
  f = TaintModule::Foo.new
  "#{f.foo}:#{v.var}"
}

# Fooのメソッドは汚れているので、セーフレベル4で実行される。
safe(1) {
  f = TaintModule::Foo.new
  expects_security_error {
    f.hoge # 内部でtaintを呼び出しているがセーフレベル4では許可されない
  }
}

実行結果です。

foo:var