セーフレベル4でのクラス定義
セーフレベル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