libyamlとmacのsharedライブラリについて
先日Ruby Yamlの脆弱性対策(CVE-2014-2525) - rochefort's blog を行ったのですが
よくわからないことがあり調べてみました。
2つの疑問
1つ目。どうして再ビルドが不要か。
sharedライブラリを使っているんだろうけど、どこでどう使っている?
2つ目。前回rbenv install時に RUBY_CONFIGURE_OPTS で enable-shared や with-libyaml-dir
を指定していないのにlibyamlの更新で事足りたのか。
(指定無しでもsharedライブラリとして扱われているのか?)
そもそも with-libyaml-dir っているんだろうか。
2つ目の方はまだよくわかってません。
psychのextconf.rbとかちらっと見たりしたのですが未解決。
とりあえず
psych.so
1つ目の方ですが、psych.rbの最初にpsych.soをrequireしています。 ./rbenv/versions/2.1.1/lib/ruby/2.1.0/psych.rb
require 'psych.so'
こいつをロードしていて、きっとlddとかしちゃうとhomebrewで入れたlibyamlを参照してるんだな
と予想してみたのですが、いくら探してもpsych.soファイルがありません。
./versions/2.1.1/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle
探している最中 psych.bundle というファイルを見つけました。
なんか怪しい。
試しにrenameしてrequireしてみるとエラーになりました。
$ ruby -e "puts require('psych.so')" /Users/rochefort/.rbenv/versions/2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- psych.so (LoadError) from /Users/rochefort/.rbenv/versions/2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require' from -e:1:in `<main>'
こいつですね。
Macのsharedライブラリ
bundleとかsoとかの関係が分からなかったので調べてみると
.soや.dylibや.aファイル、共有ライブラリなどについて調べてみた - kanonjiの日記
MacではDynamic LinkingとDynamic Loadingは厳密に区別されている。
・Dynamic Loadingに当たるものは、Mac側ではバンドルと呼ばれる。 ・Dynamic Linkingな共有ライブラリは.soではなく.dylibファイル。 ・Dynamic Loadingの方は.bundleが推奨されるが、Linuxからの移植の場合、拡張子は.soのままな事が多い。
psych.rbでは、psych.bundleをDynamic Loadingしていて
bundleの方はlibyaml系をDyamic Linkingしているという理解でいいんでしょうか。
ldd
とりあえずbunldleをlddしてみようと思ったのですが
macにはlddは無いようで、代わりにotoolというコマンドが提供されているようです。
manを見ると、いろいろoptionはあるようですが、sharedライブラリの参照であれば -L でokです。
$ otool -L ./versions/2.1.1/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle psych.bundle: /Users/rochefort/.rbenv/versions/2.1.1/lib/libruby.2.1.0.dylib (compatibility version 2.1.0, current version 2.1.0) /usr/local/lib/libyaml-0.2.dylib (compatibility version 3.0.0, current version 3.4.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) /usr/local/lib/libgmp.10.dylib (compatibility version 12.0.0, current version 12.3.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
$ ll /usr/local/lib/libyaml-0.2.dylib lrwxr-xr-x 1 rochefort staff 45 3 30 18:46 /usr/local/lib/libyaml-0.2.dylib@ -> ../Cellar/libyaml/0.1.6/lib/libyaml-0.2.dylib
このdylibはsymlinkなので、当初の予想通りsharedライブラリで
libyamlはrubyの実行時に読み込まれるものでした。
めでたし、めでたし。
おまけ
細かい検証はしていないので、私の環境はこうだったというレベルの話です。
(する元気がない。。)
enable-shared や with-libyaml-dir 指定無しのruby2.1.0
$ otool -L ./versions/2.1.0/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle ./versions/2.1.0/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle: /usr/local/lib/libyaml-0.2.dylib (compatibility version 3.0.0, current version 3.2.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) /usr/local/lib/libgmp.10.dylib (compatibility version 12.0.0, current version 12.3.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
enable-shared や with-libyaml-dir を指定したruby2.1.1
$ otool -L ./versions/2.1.1/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle ./versions/2.1.1/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle: /Users/rochefort/.rbenv/versions/2.1.1/lib/libruby.2.1.0.dylib (compatibility version 2.1.0, current version 2.1.0) /usr/local/lib/libyaml-0.2.dylib (compatibility version 3.0.0, current version 3.4.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) /usr/local/lib/libgmp.10.dylib (compatibility version 12.0.0, current version 12.3.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
libruby.2.1.0.dylib が2.1.1にはあります。
多分これがenable-sharedの差だとは思うのですが、with-libyaml-dir はよくわかりません。
ちなみに、build時のconfigureオプションは下記で見れます。
ruby2.1.0
$ ruby -rpp -rrbconfig -e "pp RbConfig::CONFIG['configure_args'].split(\"' '\")" [" '--prefix=/Users/rochefort/.rbenv/versions/2.1.0", "--with-openssl-dir=/usr/local/opt/openssl", "--with-readline-dir=/usr/local/opt/readline", "CFLAGS= -O3 -Wno-error=shorten-64-to-32 ", "LDFLAGS=-L/Users/rochefort/.rbenv/versions/2.1.0/lib ", "CPPFLAGS=-I/Users/rochefort/.rbenv/versions/2.1.0/include '"]
ruby2.1.1
$ ruby -rpp -rrbconfig -e "pp RbConfig::CONFIG['configure_args'].split(\"' '\")" [" '--prefix=/Users/rochefort/.rbenv/versions/2.1.1", "--enable-shared", "--with-readline-dir=/usr/local/opt/readline", "--with-openssl-dir=/usr/local/opt/openssl", "--with-libyaml-dir=/usr/local/opt/libyaml", "CFLAGS= -O3 -Wno-error=shorten-64-to-32 ", "LDFLAGS=-L/Users/rochefort/.rbenv/versions/2.1.1/lib ", "CPPFLAGS=-I/Users/rochefort/.rbenv/versions/2.1.1/include '"]
See Also
・.soや.dylibや.aファイル、共有ライブラリなどについて調べてみた - kanonjiの日記
・rubyをビルドしたときのconfigureオプションを表示する - Qiita
・Ruby Yamlの脆弱性対策(CVE-2014-2525) - rochefort's blog