= ping: IDN encoding of 'hostname' failed with error code 9 = 新たにインストールしたScientif Linux 6環境では`/etc/sysconfig/i18n`で`LANG="ja_JP.eucJP"`と設定を変更してあるが、 この設定で`ping hostname`コマンドを実行すると {{{ -bash-4.1$ ping nest ping: IDN encoding of 'nest' failed with error code 9 }}} というエラーが返ってくる。rendaさんが調べてみたところ * rootになって実行すれば動作する * `ping6`は動作する * Fedora14環境では`LANG=ja_JP.eucJP`で動いている * Fedora14から`ping`コマンドをコピーしてきても挙動が変わらない と言うことがわかった。エラーメッセージで検索すると[[https://www.redhat.com/archives/fedora-cvs-commits/2007-March/msg01312.html|rpms/iputils/devel iputils-20070202-idn.patch, NONE, 1.1 iputils.spec, 1.46, 1.47]]のパッチで追加された部分がエラーを出しているようだ。`ping6`が動作するのはIDNの処理が`ping`にしか追加されていないからだとわかった。 {{{ -bash-4.1$ ldd /bin/ping linux-gate.so.1 => (0x0076c000) libidn.so.11 => /lib/libidn.so.11 (0x0063e000) libc.so.6 => /lib/libc.so.6 (0x00a5d000) /lib/ld-linux.so.2 (0x00a3b000) -bash-4.1$ ldd /bin/ping6 linux-gate.so.1 => (0x007cc000) libc.so.6 => /lib/libc.so.6 (0x00a5d000) /lib/ld-linux.so.2 (0x00a3b000) }}} エラーが出ているのは`idna_to_ascii_lz`が`IDNA_ICONV_ERROR`を返している (存在しないホスト名でも同じエラーが出るので`idna_to_unicode_lzlz`ではない)からなので、 libidnのソースを追いかけてみると[[http://www.gnu.org/software/libidn/doxygen/stringprep_8h.html#a32a25e21f5a2b480c9d6b4b1930d6176|stringprep_locale_to_utf8]]が`NULL`を返しているようだ。 普通に`_LIBC`は定義されている環境のはずなので`stringprep_locale_charset`は `nl_langinfo(CODESET)`で置き換えられて"EUC-JP"が返るはず<>である。 よって`str_iconv(str, "EUC-JP", "UTF-8")`の実行結果が返ることがわかった。 では`str_iconv`に問題があるのかとlibidnのソースにあったテストコードに追記をして実行をしてみたのだが動いてしまった。 全体を`./configure --disable-csharp --disable-static --libdir=/lib`して libidn-1.18/lib/gltestsに対して次のコードを追加、 `make test-striconv`と`./test-striconv && echo ok`で行った。 {{{#!highlight c numbers=disable /* Test conversion from EUC-JP to UTF-8 with no errors. */ { static const char input[] = "\xa4\xdb\xa4\xb2"; static const char expected[] = "\xe3\x81\xbb\xe3\x81\x92"; char *result = str_iconv (input, "EUC-JP", "UTF-8"); ASSERT (result != NULL); ASSERT (strcmp (result, expected) == 0); free (result); } }}} どうしたものかと`ping`コマンドを`strace`してみたところ {{{ -bash-4.1$ strace ping nest 2>&1 | less ... open("/usr/lib/gconv/EUC-JP.so", O_RDONLY) = 3 ... open("$ORIGIN/tls/i686/sse2/libJIS.so", O_RDONLY) = -1 ENOENT (No such file or directory) open("$ORIGIN/tls/i686/libJIS.so", O_RDONLY) = -1 ENOENT (No such file or directory) open("$ORIGIN/tls/sse2/libJIS.so", O_RDONLY) = -1 ENOENT (No such file or directory) open("$ORIGIN/tls/libJIS.so", O_RDONLY) = -1 ENOENT (No such file or directory) open("$ORIGIN/i686/sse2/libJIS.so", O_RDONLY) = -1 ENOENT (No such file or directory) open("$ORIGIN/i686/libJIS.so", O_RDONLY) = -1 ENOENT (No such file or directory) open("$ORIGIN/sse2/libJIS.so", O_RDONLY) = -1 ENOENT (No such file or directory) open("$ORIGIN/libJIS.so", O_RDONLY) = -1 ENOENT (No such file or directory) ... }}} などという出力が得られた。何じゃこりゃ。ファイルパスの中に`$ORIGIN`などと紛れ込んでいたらそれは見つからないわ。 このファイル自体は`EUC-JP.so`と同じディレクトリにあるので`$ORIGIN`が`/usr/lib/gconv`に展開されれば良いのだろう。 先ほどの動作したテストコードを実行してみても {{{ -bash-4.1$ strace ./test-striconv 2>&1 | less ... open("/usr/lib/gconv/EUC-JP.so", O_RDONLY) = 3 ... open("/usr/lib/gconv/libJIS.so", O_RDONLY) = 3 ... }}} と同じディレクトリにある`libJIS.so`を発見できるのが正常であることがわかる。 `$ORIGIN`という文字列は確かに`EUC-JP.so`の中にあるようだ。 {{{ -bash-4.1$ strings /usr/lib/gconv/EUC-JP.so | grep ORIGIN $ORIGIN }}} このファイルはどこのパッケージからやってきたかというとglibcであった。 {{{ -bash-4.1$ rpm -qf /usr/lib/gconv/EUC-JP.so glibc-2.12-1.7.el6_0.3.i686 }}} そこで次はglibcのsrc.rpmから追いかけてみることにする。 specファイルを眺めていると {{{ * Mon Oct 18 2010 Andreas Schwab - 2.12-1.7.el6_0.2 - Never expand $ORIGIN in privileged programs (#643821) }}} あー……pingってsuid-bitが立ってるんだったよねーたしか。 {{{ -bash-4.1$ ls -l /bin/ping -rwsr-xr-x 1 root root 42136 11月 23 18:49 2010 /bin/ping }}} ああー……バグ報告ですか。これは。 RedHadのBugzillaでは非公開になっているが、Fedora側の情報によるとCVE-2010-3847とある。 [[http://secunia.com/advisories/41795/|GNU C Library Dynamic Linker Privilege Escalation Weaknesses (Secunia Advisory SA41795)]] Partially Fixedですかそうですか…… しかし、動作しているFedoraにも同様の修正が施されているので、 Fedoraから適切なパッチをバックポートしてくれば動くのではないだろうか。 どこのパッケージに施されたかをどうやって探そう。 Fedora14のglibcは2.13に更新されているので、これのせいで直ったとかいうことだと困るな……