requireの処理の中で、セーフレベルを一時的に 0 に下げる部分があって、この範囲を広げることで、SecurityErrorが出ないようになっていた。(3日前)
画像は、tDiaryの amazon.rbが、リポジトリから持ってきただけの素の Ruby-1.9.2dev(2009-02-03)上で動いているところ。
既に正式版がリリースされて*しまって*いる Ruby-1.9.1との違いを、先月の日記に書いた例で見ていくと、
irb192> RUBY_DESCRIPTION => "ruby 1.9.2dev (2009-02-03) [i386-mswin32_90]" irb192> $SAFE=1 => 1 irb192> require "a" SecurityError: cannot load from insecure path - Y:/.../Desktop/a.rb from (irb):3:in `require' from (irb):3 from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>' irb192> require "a.rb" SecurityError: cannot load from insecure path - Y:/.../Desktop/a.rb from (irb):4:in `require' from (irb):4 from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>' irb192>
2009-02-03版の ruby-1.9.2devでは、$SAFE=1のとき、カレントディレクトリのスクリプトを requireできない。これは $:($LOAD_PATH)に汚染されていない "." が含まれていようと、require の引数の文字列が汚染されていなかろうと、requireできない。見つけた抜け道は、絶対パスで requireするか、$:($LOAD_PATH)にカレントディレクトリを絶対パスで追加すること("."が含まれる場合はそれより前に追加する必要もある)。
ruby-1.9.1の結果は Release Candidateのときと変わらず、
irb191> RUBY_DESCRIPTION => "ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-mswin32]" irb191> $SAFE=1 => 1 irb191> require "a" SecurityError: Insecure operation - require from (irb):3:in `require' from (irb):3 from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>' irb191> require "a.rb" a.rb required. => true irb191>
ruby-1.9.1では、拡張子を付けてやるとカレントディレクトリのスクリプトも requireできる。拡張子を付けないときに requireできないのは ruby-1.9.2devも同じだが 、ruby-1.9.1には ruby-1.9.2devにない爆弾がある。$SAFE=1のときの拡張子を付けない requireは、添付ライブラリの requireであっても失敗したりする。
irb191> $SAFE=1 => 1 irb191> require "stringio" SecurityError: Insecure operation - require from (irb):2:in `require' from (irb):2 from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>' irb191> require "stringio.so" => true irb191>
これが原因で、tDiaryを ruby-1.9.1で動かすのは絶望的だと思っている*。(ruby-1.9.1はリリースされちゃったし、スクリプトで対応できる範囲を超えているから)
この部分は SecurityErrorが出ない方向に修正されると思っていたから、ruby-1.9.2devで両方のパターンが SecurityErrorになったのは意外。
ruby-1.9.2devでは、汚染されたパスが $:($LOAD_PATH)のどの位置にあるかが重要。
irb192> $SAFE=1 => 1 irb192> $:.unshift "!tainted!".taint => ["!tainted!", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2/i386-mswin32_90", "."] irb192> require "cgi" SecurityError: cannot load from insecure path - Y:/.../Desktop/!tainted!/cgi.rb from (irb):3:in `require' from (irb):3 from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>' irb192> $:.push $:.shift => ["C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2/i386-mswin32_90", ".", "!tainted!"] irb192> require "cgi" => true irb192>
ruby-1.9.2devでは、$SAFE=1で、汚染された LOAD_PATHからスクリプトを requireすることはできないが、汚染されていない LOAD_PATHからスクリプトを先に見つけた場合は、requireに成功する。ruby-1.9.1(とruby-1.8.7-p72)ではどうだったかというと、より厳しくて、
irb191> $SAFE=1 => 1 irb191> $:.unshift "!tainted!".taint => ["!tainted!", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/i386-mswin32", "."] irb191> require "cgi" SecurityError: Insecure operation - require from (irb):3:in `require' from (irb):3 from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>' irb191> $:.push $:.shift => ["C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/i386-mswin32", ".", "!tainted!"] irb191> require "cgi" SecurityError: Insecure operation - require from (irb):5:in `require' from (irb):5 from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>' irb191>
ruby-1.9.1では、汚染されたパスが一つでも $:($LOAD_PATH)に含まれると、(相対パスでの) requireはできない。絶対パスならできるが、そんな書き方はしないので $:($LOAD_PATH)に追加するパスは常に untaintしなければならない。
requireしたときのカレントディレクトリの扱いに、不満が残る。
多分、従来の Ruby、ruby-1.9.1や ruby-1.8.7は $:($LOAD_PATH)の要素の汚染状況なんて気にしていなかった。$:に含まれるか含まれないかだけが重要。2005年から現在まで変わっていない、リファレンスマニュアルのこの記述がそれを物語っていないか。
Level 1以上では起動時に以下の違いがある
- 環境変数 RUBYLIB を $: に加えない
- カレントディレクトリを $: に加えない
- (以下略)
その方針に異議を唱えるものではないけれど、この方式には、セーフレベルによる分岐が起動時に限定されるという制限がある。コマンドラインオプション -T を指定したときにしか有効にならず、$SAFEを使ってセーフレベルをコントロールするシナリオでは機能しない。
ruby-1.9.2devは、$:($LOAD_PATH) の要素の汚染状況に注目することで、$SAFEを使ってセールレベルをコントロールする場合でも「環境変数 RUBYLIB を $: に加えない」「カレントディレクトリを $: に加えない」のと同等の制限を課せる可能性を持っている。つまり、「環境変数RUBYLIBとカレントディレクトリは常に $:($LOAD_PATH)に追加される。ただし汚染された状態で。」ということ。
それなのに現在の ruby-1.9.2devの、$SAFE=1の下での requireに対するカレントディレクトリの扱いは、ruby-1.8.7より、むしろ退化している。
ruby-1.8.7では $:($LOAD_PATH)に "." を追加したり取り除いたりすることでカレントディレクトリの扱いを、セーフレベルによらず、スクリプトがコントロールできた。
拡張子の有無で結果が変わる、動作に筋の通らない ruby-1.9.1の requireは論外として、
ruby-1.9.2devでは、カレントディレクトリのスクリプトの requireは $:($LOAD_PATH)によらず、SecurityErrorになる。カレントディレクトリを絶対パスで $:($LOAD_PATH)に追加することでコントロール可能だが、既に含まれているかもしれない "." が邪魔をする。ruby-1.9.2devは、$:($LOAD_PATH)に含まれる "." の汚染状況(あるいは "."が $:に含まれないこと)によってのみカレントディレクトリの扱いを変えるべきで、カレントディレクトリが特別に SecurityErrorになる、現在の ruby-1.9.2devには同意できない。
セールレベル1ではまだスクリプトを信用しているのだから、少なくとも ruby-1.8.7と同等のコントロールをスクリプトに渡して欲しい。
requireが利用する File.expand_pathの仕様によりカレントディレクトリからの相対パスが汚染されるのだろうが、File.expand_pathは requireが $:($LOAD_PATH)に依拠していることを知らないのだから requireが何とかすべき。
* その後の変更で、ruby-1.9.1らしき挙動の requireを検出したときはセーフレベルを 1から 0に下げてプラグインを実行することになっている。セーフレベル0なら今回のことは関係ないから。セーフレベルを下げるという発想は全く頭になかった。なんか、こう、負けた気がするからだろう。ruby-1.9.0だとセキュアモード(セーフレベル4)で動かないという話もあったけどどうなったんだろう。
最終更新: 2013-03-10T03:39+0900
パソコンが 二台以上になって以来、必要だと感じていた NASを手に入れた。電源の ON/OFFをスケジュールすることはできないし、PC連動機能(PCに常駐ソフトをインストールして、定期的に pingを送信することで NASを目覚めさせておく機能)は使わないが、普段の消費電力の小ささ(平均:10W、最大:13W)でそこは目をつぶる。
一番にやったのは mp3をごっそりコピーして、DLNAサーバーとして機能させること。LinkStationを手に入れてやっと、インターネットラジオ専用機となっていた VGF-WA1が本領を発揮している。
転送速度は 100Mbps前後で一定している。一応ギガビットLANなんだけど、ネックはケーブルかフレームサイズか HDDの読み書き速度か、あるいは LinkStationの CPUか。直付けの HDDよりはっきり遅いから、Media Player Classicは再生前にすべてのファイルにアクセスしているのだな(=ファイル数に比例して、なかなか再生が始まらない)、とか発見がある。
WebUIで一部の設定が可能にしたついでに、曲情報の表示と再生コントロールを可能にすれば良かった。そうすればさんざん要望されている画面付きリモコンの役を PSPが担うことができた。
アルバムを再生し終わるたびに だんまり になるのが面倒くさい。そのたびに、再生ボタンを押すか、本体の画面をみながら次に再生したい曲を選ぶか、リモコンのフォルダ移動ボタンで次のアルバムを再生するかの操作を求められる。面倒くさい。デフォルトで次のアルバムを再生しようよ全曲リピートに。その他の動作は一曲リピート、アルバムリピートで指示できるだろうし。
操作を求められるたびに、インターネットラジオを再生するならこんな手間はない、と再生ソースを変更する誘惑に駆られる。
CDプレイヤー感覚でライブラリを扱わないで欲しい。ことに VGF-WA1は再生コントロールが貧弱(一度に 4行しか表示できない本体液晶。13ボタンのリモコン)なのだから、ユーザーの限られた選択肢から適切なデフォルトを選択するのも簡単だったでしょう。
次のファームウェアか次の機種に期待しています。
全曲リピートに しておくと希望通り隣のアルバムを再生してくれるみたい。(2013-03-09)
#<Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ASCII-8BIT> (plugin/00default.rb):571:in `comment_form_text' (plugin/00default.rb):616:in `comment_form' (TDiary::Plugin#eval_src):79:in `block in eval_src' Y:/server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:787:in `eval' Y:/server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:787:in `block in eval_src' Y:/server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:112:in `block in safe'
なにが ASCII-8BITだったかというと Cookie。
plugin/00default.rb:575: #{comment_name_label}:<input class="field" name="name" value="#{h( @conf.to_native(@cgi.cookies['tdiary'][0] || '' ))}">
ならばと UTF-8への変換を試みたならば
@cgi.cookies['tdiary'][1].encode("utf-8") #=> #<Encoding::UndefinedConversionError: "\xE3" from ASCII-8BIT to UTF-8>
クッキーみたいに何が送られてくるかわからないものは、慎重に慎重にエラーに備えて取り扱わないといけない、ということですね。(面倒くさいなー)
CGIパラメータなんかも、取り扱い注意、だよね。cgi.rbの支援はないのかな?(他力本願)
「Testing tDiary on Ruby1.9.1」と題した日記にも関わらず、少しの間、うっかり 1.8.7で動かしていた。そのせいでキャッシュが原因のエラーが出たし、キャッシュを削除したら今度はクッキーが原因のエラーが出たという次第。
サーバーの Rubyを 1.8.7から 1.9.1にアップデートしたタイミングでそのサーバーの日記を閲覧できなくなる人(過去3か月間にコメントした人限定)が続出、とか。ないだろうか。
cgi.rbも変わっていたのでした。
どちらも日付が今日(2009-01-24)だ! Googleクローリング早い。
tDiaryの文脈で Rackの名前を見かけてたんだけど、名前から Rakeのようなものを想像していた。Web方面だったのね。
>irb irb(main):001:0> RUBY_DESCRIPTION => "ruby 1.8.7 (2008-05-31 patchlevel 0) [i386-mswin32_90]" irb(main):002:0> $SAFE=1 => 1 irb(main):003:0> $:.unshift "hoge".taint => ["hoge", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8",..., "."] irb(main):004:0> require 'cgi' SecurityError: Insecure operation - require from (irb):4:in `require' from (irb):4 from :0 irb(main):005:0>
1.8.7でもこうなのだから知らない俺が抜けているのだが、$SAFE=1のときに汚染された文字列を $LOAD_PATHに追加する(pushでも unshiftでも)と、一切の requireができなくなる。
期待したいのは、hoge/cgi.rbや hoge/cgi.soなどが存在するときには、このパスは汚染されているので SecurityError。存在しないときはファイルの探索を続けて C:/Program Files (x86)/ruby/lib/ruby/1.8/cgi.rb (このパスは汚染されていないはず)を読み込む、という動作なのだけど……。
実際はそうではないのだから tDiaryの
tdiary.rb:12: $:.insert( 1, File::dirname( __FILE__ ) + '/misc/lib' )
というのは __FILE__ が汚染されているときに、わりと危険な操作ということになる。問題が起きないのは SAKURAのレンタルサーバの Rubyが 1.8.6だからなのか、__FILE__、File.dirname(__FILE__) が汚染されていることが稀だからなのか。(汚染されていることが実際にあるのは、20090117p01で書いたように、untaintすることで状況が改善したことから推測できる)
問題が起きないのは SAKURAのレンタルサーバの Rubyが 1.8.6だからなのか、__FILE__、File.dirname(__FILE__) が汚染されていることが稀だからなのか。
両方でした。__FILE__が汚染されているのは Ruby-1.9.1RC1だから(多分)。
$SAFE=1のときに汚染された文字列を $LOAD_PATHに追加する(pushでも unshiftでも)と、一切の requireができなくなる。
書きながら誇張だとは気付いていたのだけど(一切の、の部分が)、そうでない例を自分で見つけたので追記(2009-02-02)。
Windowsで、フルパスで、あるいは拡張子(.rb)なしのフルパスでなら requireできる。
Y:\...\Desktop\a>irb irb(main):001:0> RUBY_DESCRIPTION => "ruby 1.8.7 (2008-05-31 patchlevel 0) [i386-mswin32_90]" irb(main):002:0> $SAFE=1 => 1 irb(main):003:0> $:.push "".taint => ["C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby/1.8/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/1.8/i386-mswin32_90", ".", ""] irb(main):004:0> require "a" SecurityError: Insecure operation - require from (irb):4:in `require' from (irb):4 from :0 irb(main):005:0> require "a.rb" SecurityError: Insecure operation - require from (irb):5:in `require' from (irb):5 from :0 irb(main):006:0> require "./a.rb" SecurityError: Insecure operation - require from (irb):6:in `require' from (irb):6 from :0 irb(main):007:0> require "Y:/.../Desktop/a/a" => true irb(main):008:0> require "Y:/.../Desktop/a/a.rb" => false irb(main):009:0> require "a" SecurityError: Insecure operation - require from (irb):9:in `require' from (irb):9 from :0 irb(main):010:0>
step1 load.c:147 (rb_feature_p) if (!load_path) load_path = rb_get_expanded_load_path(); step2 load.c:44 (rb_get_expanded_load_path) VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil); step3 Insecure Operation - require (SecurityError)
いました。Ruby1.9.1で SecurityErrorを量産する rb_get_expand_path()が。どうも、汚染された load_pathの一つを展開しようとして SecurityErrorになってる気がする。
$:($LOAD_PATH)の要素が汚染されてるのは、こちらの責任では?と思って確かめてみた。
SecurityErrorの直前で、$:の各要素が tainted?かどうかを TDiary::Config#debugを使って出力した結果。
D, [2009-01-17T23:36:46.289008 #1212] DEBUG -- : false Y:/server_root/www/ds14050/tdiary_on_ruby191 D, [2009-01-17T23:36:46.289008 #1212] DEBUG -- : true Y:/server_root/www/ds14050/tdiary_on_ruby191/misc/lib D, [2009-01-17T23:36:46.289008 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/site_ruby/1.9.1 D, [2009-01-17T23:36:46.289985 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/site_ruby/1.9.1/i386-msvcr90 D, [2009-01-17T23:36:46.289985 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/site_ruby D, [2009-01-17T23:36:46.289985 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/vendor_ruby/1.9.1 D, [2009-01-17T23:36:46.289985 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/vendor_ruby/1.9.1/i386-msvcr90 D, [2009-01-17T23:36:46.290961 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/vendor_ruby D, [2009-01-17T23:36:46.290961 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/1.9.1 D, [2009-01-17T23:36:46.290961 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/1.9.1/i386-mswin32_90 D, [2009-01-17T23:36:46.290961 #1212] DEBUG -- : false .
ひとつ、ありましたね。tDiaryが該当パスを $LOAD_PATHに挿入する部分で、下のように untaintをつけるだけで理不尽な SecurityErrorが解決しました。(ただし、ASRでは依然 SecurityErrorになる。解決したのは、20090116p01で書いたように、load.cの 501行目をコメントアウトした Ruby-1.9.1RC1での話)
-tdiary.rb:12: $:.insert( 1, File::dirname( __FILE__ ) + '/misc/lib' ) +tdiary.rb:12: $:.insert( 1, File::dirname( __FILE__ ).untaint + '/misc/lib' )
今回の一連の流れ(20090113p01、20090114p01、20090116p01)で、$SAFE=1が、SecurityErrorで使い物にならなくなる(>添付ライブラリの requireにも失敗する)、二つのルートが見つかった。それらは requireするライブラリの拡張子を明示したり、$LOAD_PATHの中身をすべて untaintすることで回避できたり、load.cの一行をコメントアウトしたりで回避できたが、スクリプトで対処すべきものではないと考える。file_expand_pathが $SAFE>0のとき、汚染された入力を一切受け付けないという前提のもと、(rb_)file_expand_pathを呼び出しているコードを見直すか、file_expand_pathが汚染された入力を受け入れて適切に処理するか、どちらかの変更が必要だと思う。「file_expand_path()の結果が汚染された入力や $LOAD_PATHの汚染された一要素に基づくとき、その展開されたパスも汚染されている。」「$SAFE=1のとき、最終的に requireするファイルのパスが、汚染された引数や、$LOAD_PATHの汚染された要素に基づくとき、SecurityError。」というのではいけないのだろうか。Ruby-1.8.7はそのへんうまくやっているのだが……。
改めてドキュメントを読んだら、汚染された文字列を引数にした Fileのクラスメソッド、インスタンスメソッドは禁止されていた。($SAFE=1のとき)
ドキュメントに従うなら rb_file_expand_pathが SecurityErrorを出すのは正しいのかも(Ruby-1.8.7がまちがっている)。それならば、$LOAD_PATHの汚染された要素を不用意に展開しようとして SecurityErrorを出したり(load.c:44:rb_get_expanded_load_path)、もともと汚染されていなかった文字列を複数回展開しようとして SecurityErrorを出したり(load.c:501:search_required)するほうを修正しなければ。
私見では、(最下層で実際の仕事を行う)file_expand_pathは汚染フラグを適切に伝播させるものの SecurityErrorは出さないでおき、(スクリプトから呼ばれる)File.expand_pathの実体である rb_file_s_expand_pathか、file_expand_pathに仕事を丸投げする rb_file_expand_pathでセーフレベルに基づくチェックを行うのが、呼び出し側にとって便利だと思う。
tDiaryのプラグインの recent_list.rbを書き換えたのは、今思えば不要だったみたいだ。(Rubyの方が変わるに違いないもの)
20090113p01や20090114p01で発生したエラーを起こす最小のスクリプトとそれを回避する方法。
>type a.rb puts "a.rb required." >ruby19 -v ruby 1.9.1 (2008-12-30 patchlevel-0 revision 21203) [i386-mswin32_90] >ruby19 -e "$SAFE=1; require 'a'" -e:1:in `require': Insecure operation - require (SecurityError) from -e:1:in `<main>' >ruby19 -e "$SAFE=1; require 'a.rb'" a.rb required.
二つの違いは requireするライブラリの拡張子(.rb)を明示しているかどうか。拡張子なしの場合に発生する SecurityErrorは間違いだと思う。そうでないと $SAFE = 1がまるで使い物にならない。添付ライブラリだってまともに動かなくなるんだから。
ところで、Ruby 1.9 - 1.9.1 RC2 issues - Ruby Issue Tracking Systemにはチケットを作成するためのフォームがない。ruby-dev MLはアーカイブをときどき閲覧しているが購読はしていない。是非ともこの SecurityErrorは消して欲しいのだが、報告を受け付ける間口が狭い。直通ルートがない。どうすべ。
どうすべ、と言ってる間に原因究明。
load.c:500: type = rb_find_file_ext(&tmp, loadable_ext); load.c:501: tmp = rb_file_expand_path(tmp, Qnil);
501行目が不要に思える。そしてこれが SecurityErrorの原因。rb_find_file_extは内部で rb_file_expand_pathや file_expand_pathを呼び、その結果を tmpにコピーしてくれている。二度目を呼ぶ必要はないのでは? rb_file_expand_pathは適宜汚染されたStringオブジェクトを返し、また $SAFE>0のとき、汚染された引数を SecurityErrorで拒絶するので、複数回の (rb_)file_expand_path呼び出しは容易に SecurityErrorを引き起こす。これは Ruby1.9.1の、Ruby1.8.7とは異なっている動作。
>irb irb(main):001:0> File.expand_path("a") => "Y:/a" irb(main):002:0> File.expand_path("a").tainted? => true irb(main):003:0> File.expand_path(File.expand_path("a")) => "Y:/a" irb(main):004:0> $SAFE=1 => 1 irb(main):005:0> File.expand_path(File.expand_path("a")) => "Y:/a" # $SAFE>0で、taintedな文字列でも展開する。(Ruby1.8.7) irb(main):006:0> exit >irb19 irb(main):001:0> File.expand_path("a") => "Y:/a" irb(main):002:0> File.expand_path("a").tainted? => true irb(main):003:0> File.expand_path(File.expand_path("a")) => "Y:/a" irb(main):004:0> $SAFE=1 => 1 irb(main):005:0> File.expand_path(File.expand_path("a")) # $SAFE>0で、taintedな文字列を引数にすると SecurityError (Ruby1.9.1RC1) SecurityError: Insecure operation - expand_path from (irb):5:in `expand_path' from (irb):5 from C:/Program Files (x86)/ruby/bin/irb19.bat:20:in `<main>' irb(main):006:0>
問題設定が間違っていたのか? load.cの一行をコメントアウトしたことで、たしかに一つの SecurityErrorは消えたが tDiaryは動かない。20090114p01のエラーがまだ出る。
ただ、20090114のタイトルにちらっと書いた、open-uriの SecurityErrorはでなくなってる。
>irb19 (野良パッチ済み) irb(main):001:0> $SAFE=1 => 1 irb(main):002:0> require 'open-uri' => true irb(main):003:0> open 'http://www.example.com' => #<StringIO:0x2b8e924> irb(main):004:0>
比較として ASRでエラーが出るのを確認する。ただ、ASRでも二回目以降の openはエラーにならない。謎の挙動。この SecurityErrorも本来発生すべきものではないのだろう。
>"C:\Program Files (x86)\ActiveScriptRuby-1.9.1\bin\irb.bat" irb(main):001:0> $SAFE=1 => 1 irb(main):002:0> require 'open-uri' => true irb(main):003:0> open 'http://www.example.com' SecurityError: Insecure operation - write from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `write' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `<<' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `<<' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:322:in `block (3 levels) in open_http' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:373:in `call_block' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:364:in `<<' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:88:in `read' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2333:in `read_body_0' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2288:in `read_body' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:321:in `block (2 levels) in open_http' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1120:in `block in transport_request' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2251:in `reading_body' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1119:in `transport_request' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1103:in `request' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:312:in `block in open_http' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:564:in `start' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:306:in `open_http' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:767:in `buffer_open' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:203:in `block in open_loop' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:201:in `catch' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:201:in `open_loop' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:146:in `open_uri' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:669:in `open' from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:33:in `open' from (irb):3 from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:21:in `<main>' irb(main):004:0> open 'http://www.example.com' => #<StringIO:0x2b611a4> irb(main):005:0>
引き続き rexml/source.rb:16の requireが SecurityErrorになる原因を探る。(tDiaryを起動しないと再現させられないのが辛い)
方針は昨日書いたとおり、プラグインが自由に日記データを取得できる手段を提供した。
日記を一日書いたとたんにエラーということはなくなったみたい。
$SAFE=1で requireが失敗する(ファイル名の untaintもしているのに)のがそもそもおかしい。open-uriや rexmlで同様に requireで SecurityErrorエラーが生じていることからも、疑惑の目がウチの Rubyに向いてきた。「1.9.1RC1だから」ではなく「ウチでコンパイルしたから」、あるいは(開発者に)利用者が少なそうな 「Windows(それも Vista)だから」なのかもしれない。
ASRをインストールしてみたけどダメだった。同じ。tDiaryをセキュアモードで動かしているわけではないので Rubyのセーフレベルは最高でも 1。taintedな文字列を使った requireが失敗するならわかる。でも rexml/source.rbの 16行目は「require 'stringio'」だ。べったべたのリテラルだ。
500 Internal Server Error Insecure operation - require (SecurityError) C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/source.rb:16:in `require' C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/source.rb:16:in `create_from' C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/parsers/baseparser.rb:146:in `stream=' C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/parsers/baseparser.rb:123:in `initialize' C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:9:in `new' C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:9:in `initialize' C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/document.rb:228:in `new' C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/document.rb:228:in `build' C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/document.rb:43:in `initialize' (plugin/amazon.rb):231:in `new' (plugin/amazon.rb):231:in `amazon_get' (plugin/amazon.rb):322:in `isbn_image' (TDiary::Plugin#eval_src):32:in `block in eval_src' Y:/.../server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:787:in `eval' Y:/.../server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:787:in `block in eval_src' Y:/.../server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:112:in `block in safe'
>clipboard
'clipboard' は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。 >clip
情報: "CLIP /?" と入力すると使用法が表示されます。 >clip /?
コマンド ライン ツールの出力を Windows クリップボードにリダイレクトします。(やっぱりあるよねー。手コピしなくてすんでよかった。なお XPには……)最終更新: 2015-07-09T23:54+0900
tdiary/trunk (r3394) を ruby 1.9.1 (2008-12-30 patchlevel-0 revision 21203) [i386-mswin32_90] で動かしてみた。
dot.htaccessと tdiary.conf.beginnerを編集&リネームして、トップページの表示と一通りの設定変更を済ませて、記念すべき最初の書き込み。……トップページすら表示されなくなりました。
Insecure operation - require (SecurityError) Y:/.../tdiary_on_ruby191/tdiary.rb:434:in `require' Y:/.../tdiary_on_ruby191/tdiary.rb:434:in `block in load_styles' Y:/.../tdiary_on_ruby191/tdiary.rb:433:in `glob' Y:/.../tdiary_on_ruby191/tdiary.rb:433:in `load_styles' Y:/.../tdiary_on_ruby191/tdiary/defaultio.rb:142:in `initialize' Y:/.../tdiary_on_ruby191/tdiary.rb:1069:in `new' Y:/.../tdiary_on_ruby191/tdiary.rb:1069:in `initialize' Y:/.../tdiary_on_ruby191/tdiary.rb:1660:in `initialize' Y:/.../tdiary_on_ruby191/tdiary.rb:1858:in `initialize' (plugin/recent_list.rb):39:in `new' (plugin/recent_list.rb):39:in `block (3 levels) in recent_list' (plugin/recent_list.rb):37:in `reverse_each' (plugin/recent_list.rb):37:in `block (2 levels) in recent_list' (plugin/recent_list.rb):36:in `reverse_each' (plugin/recent_list.rb):36:in `block in recent_list' (plugin/recent_list.rb):35:in `catch' (plugin/recent_list.rb):35:in `recent_list' (TDiary::Plugin#eval_src):67:in `block in eval_src' Y:/.../tdiary_on_ruby191/tdiary.rb:787:in `eval' Y:/.../tdiary_on_ruby191/tdiary.rb:787:in `block in eval_src' Y:/.../tdiary_on_ruby191/tdiary.rb:112:in `block in safe'
プラグイン:recent_listが原因。(外したら解決した)
$SAFE==1の状況で TDiaryMonth.new()するのがダメっぽい。
recent_list()を呼ばれたときに、そのたびに、TDiaryMonth.new()するんでなくて、読み込まれたときに必要なデータを準備しておけばいいんじゃないか、とか思ったけど、evalで TDiaryMonthクラスにアクセサを追加したりしているあたり*、反則。泥縄の対応では気が済まない。プラグインが日記データを要求できるようなインターフェイスが求められている(現在は TDiaryXXXX#initializeで読み込まれたもののみ、Plugin@diariesからアクセスできる)。然るべき手段を用意したのち、recent_list.rbはそれを利用するべき。
* 歴史的経緯>http://kitaj.no-ip.com/tdiary/20021106.html#p03
最終更新: 2013-10-20T21:53+0900
ケンジントンの新作: SlimBlade Trackballが発売予定なのを昨日知ったのだけど、もうロジクールのトラックボールを注文していたのでした。(量販店には置いてなかったのでアマゾンで)
しばしば 10000円を超えるトラックボール界にあって売価 3000円の入門機なれどそのスペックが侮れないのはこちらを参照のこと > http://mineko.fc2web.com/box/tb-room/items/logitech-st-45upi.html ここを読んでこのトラックボールに決めました。
一瞬で慣れた。渋かったボールの転がりもすぐに滑らか。慣らしが必要なのね。やけに手前にあると思った右ボタン(大と小)も、それぞれ薬指の先と第二関節(根っこの方)で押せばいいと気付いた。
SetPointにその機能があった。Universal Scroll。デフォルトで右側の小さいボタンに割り当てられている。モードのオンとオフに 2クリック必要(オフにするのはどのボタンでも可能)なのは正直面倒くさいけど、すぐに意識せずに済むようになるはず。ただ、上下左右にスクロールが自由自在というのは諸刃の剣で、下方向だけにスクロール、右方向にだけスクロールということは不可能。サクラエディタでテキストファイルをスクロールしながら閲覧するのが非常に煩わしかった。
キーボードの Ctrlを押しながらだと、Firefoxの文字サイズを変更することも可能。
キーボードの Ctrlを押しながらでも、Explorerの表示モードを変更することは不可能。
スクロールバーの付いてるものには大抵有効だけど、展開する前のドロップダウンリストを動かしたり、直線上のつまみを移動したり、Media Player Classicのボリュームを上げ下げしたりはできない。
Universal Scrollの機能はスクロールであってホイール(メッセージの送信)ではない、ホイールの一機能を担うだけ、ということか。
Universal Scrollボタンを押すと、ポインタの真下のアプリケーションがアクティブになるのも困ったところ。そういうのを好む人もいるのだろうけど、俺が主に注目しているのはフォーカスであってポインタではないし、文字を読むときに邪魔だからとポインタを端っこにやったりもする。その状態で、スクロールをしたい。
スクロールモードを解除した後もカーソルを移動させるまでカーソル画像が元に戻らないものがある > Firefox。現在のモードがわからなくなるのでけっこう不快。
Firefoxのテキストエリアにフォーカスがあるとき、キャレットが同時に動いてしまっておかしなことになる。
素早い操作は無視される。トラックボールの良さが台無し。速度が遅く、スクロール量がボールの回転とリニアに対応していないために、たるい。
スクロール速度の設定もあるにはあるのだけど、対象アプリケーションごとに感度がまちまちなので、というか IEコンポーネントに限ってスクロールが超微速なんだけど、それにあわせて一律の設定を速くはできない。かといって設定の遅さをボールの回転速度で補うことができないのは既に書いたとおり>「素早い操作は無視される。」
<追記 @2010-01-25>Universal Scrollで Safari 4のスクロールはできません。主要なブラウザだし、最新の SetPointではできる可能性もあるけど。</追記>
<追記 @2010-03-28>Universal Scrollで Opera 10.51のスクロールもできない。以前はどのブラウザでも使えたと思ったが……。SetPointを最新の 6.0にしたら結果は違うかもしれないが SetPointに期待はできないので試さない。Firefox(3.6)と IE(8)は変わらずページのスクロールが可能で、Google Chrome4.1でもできるのだが、困ったことにどのブラウザもスクロール速度が異なる。(速 Chrome > Fx > IE 遅)</追記>
<追記@2011-01-12>Opera 11.00は Universal Scrollでスクロールできる。</追記>
キーボードとの使い分け。思い通りにポインタが動くから今までキーボードを使っていた操作もついついトラックボールでやってしまう。マウスがポインティングデバイスとして不便だから、ショートカットキーを登録したボタンがたくさん必要になったり、キーボードの補助が必要だったりしたのだ。
4ボタンしかない TM-150で唯一余っているといっていい左の小ボタン(デフォルトで「戻る」ボタン)を多機能ボタンにすること。ボタンを押しながらのボールの上下左右に機能を割り当てたら 1ボタンで 4ボタン相当。(注意しないといけないのは、ボールを厳密に上下左右に回転させることはできないので一定以上の移動量を以て方向を判断してもらわないといけないこと)
SetPointにその機能があるのか、他のプログラムでできるのか、これから調べる。
最新ではない 4.00を引き続き使ってるけど、Marble Mouse (ST-45UPi)の名前と画像が表示されて、使えている。(マウスの名前は 1000070.xmlを修正して変更できる)
画像は SetPointに現れた新しいタブ。トラックボールの Y軸(X軸)方向を決められるので、どんな角度で持っても違和感なく操作できる。Z軸はもちろん変更できない。平面に置いて使うのが前提。
右利きだけどキーボードの左に置いて左手で使ってる。ボタン割り当てを左利き用にはしてなくて、薬指で左クリック、親指で右クリック。薬指をコの字に折り曲げて第一関節から爪にかかる面で戻る。親指は常に右小ボタンに乗ってて Universal Scroll。手のひらは完全に重さを預けてる(Logicoolロゴは消えた)。加速なしで 90から 100度の回転で画面の端から端まで(1920ピクセル)移動する。
スクロールモードなんて必要なかった!!ボールをひねるだけ!
メディアモード、ビューモード切り替えでボールの役割をスイッチ。SetPoint並みにカスタマイズがきけば、望んでいた、ジェスチャモードによる仮想的なボタン追加が実現する。
デザインも良い。なにこのボールの大きさと露出量。
20081231に書いた以上のものが手に入る。(かもしれない。手にとって実際に使用してみるまでは……)
発売日はいつですかー。64-bit Vistaでも使えますかー。