セーフレベル4でのインスタンス変数の変更ではまる
セーフレベル4でも、汚染されたオブジェクトが対象であれば、インスタンス変数の変更が可能です。ただし、更新するインスタンス変数がクラス内で1度も使われていない場合、SecurityErrorとなるのでご注意。
# 指定のSAFEレベルでブロックを実行する。 def safe( level ) Thread.fork { $SAFE = level yield if block_given? }.value end # テスト用クラス class Foo def not_called @hoge end end foo = Foo.new foo.taint #汚染 # 汚染たオブジェクトのインスタンス変数は、セーフレベル4でも変更できる。 safe( 4 ) { foo.instance_variable_set("@hoge", "var") } # ただし、インスタンス変数がクラス定義内で1度も使用されていない場合、 # 「Insecure: can't modify instance variable (SecurityError)」となる。 safe( 4 ) { foo.instance_variable_set("@var", "var") }
実行結果です。@hogeは問題なく変更できますが、未知のインスタンス変数@varを変更するところで、「Insecure: can't modify instance variable (SecurityError)」が発生します。
xxx/instance_variable_set.rb:25:in `instance_variable_set': Insecure: can't intern tainted string (SecurityError) from xxx/instance_variable_set.rb:3:in `value' from xxx/instance_variable_set.rb:3:in `safe' from xxx/instance_variable_set.rb:24
内部的にインスタンスとかクラスの拡張みたいな扱いになっているのかな?なんとなく納得できる挙動である気はしますが。「セーフレベル4ではオブジェクトのインスタンス変数は変更できない」のかと思ってさんざん迷走してしまった・・・。orz.